当前位置:首页>python>《Python 从入门到精通》037|集合 set 入门:去重为什么这么高效

《Python 从入门到精通》037|集合 set 入门:去重为什么这么高效

  • 2026-10-11 08:39:31
《Python 从入门到精通》037|集合 set 入门:去重为什么这么高效

前面我们已经学过列表、元组、字典。

它们各有各的用处,但有一种需求,在实际开发里出现得特别频繁:

去重。

比如一份用户名单里,有重复名字。 一批商品标签里,有重复标签。 一堆日志编号里,有重复编号。 一个爬虫抓下来的链接列表里,也可能重复一大堆。

如果你还用列表硬着头皮一个个判断,代码不但啰嗦,而且效率不高。

这时候,集合就该出场了。

集合这个东西,刚学的时候很多人会觉得它存在感不强。可一旦开始做数据处理,你会很快发现:

它简直就是为 去重 和 快速判断某个值在不在 而生的。

这一章,我们就把集合彻底讲明白。

一、什么是集合

在 Python 里,集合的名字叫 set。

它也是一种容器,可以存放多个数据。 但它和列表、元组最大的区别有两个:

集合里的元素不能重复 集合是无序的

先看一个最简单的例子:

nums = {1, 2, 3, 4}print(nums)print(type(nums))

输出:

{1, 2, 3, 4}<class 'set'>

这就是一个集合。

它外面用的是大括号,看上去和字典有点像,但它不是字典。

字典长这样:

{'name': '张三', 'age': 18}

里面是 键:值 的结构。

而集合长这样:

{1, 2, 3, 4}

里面只有值,没有键。

所以你可以这样记:

大括号里如果是 成对的键值,那是字典 大括号里如果只是 一堆单独的值,那是集合

二、集合最核心的特点:自动去重

这是集合最有代表性的能力。

看代码:

nums = {1, 2, 3, 2, 1, 4, 3}print(nums)

输出:

{1, 2, 3, 4}

你明明写了重复的值,但最后打印出来时,重复项自动没了。

这就是集合最核心的特性:

只保留不重复的元素

很多人第一次看到这里,会觉得有点神奇。 其实你不用一开始就深究底层原理,先把它当成集合的天然规则就行。

你往集合里放重复值,它不会报错,也不会存两份。 它只留一份。

所以集合特别适合做这类事情:

名单去重 标签去重 关键词去重 订单编号去重 链接去重

一句话概括:

只要你脑子里出现 去重 这两个字,就要想到 set。

三、集合为什么说是无序的

先看这个例子:

nums = {10, 3, 8, 1, 6}print(nums)

你可能会发现,输出顺序和你写进去的顺序不一定完全一样。

这就是因为集合是无序的。

这里的无序,不是说它乱七八糟完全不能用,而是说:

集合不靠位置来管理元素

也正因为如此,集合不像列表那样支持索引。

你不能这样写:

nums = {10, 20, 30}print(nums[0])

这会报错。

为什么?

因为集合根本就没有 第 0 个、第 1 个 这种概念。 它只关心某个元素在不在,不关心它排第几。

这一点非常重要。

列表的思维是:

第几个位置放了什么

集合的思维是:

某个值有没有出现

这两个方向完全不同。

四、空集合怎么写

这里有个新手特别容易踩坑的地方。

你可能会很自然地写:

data = {}

然后以为自己创建了一个空集合。

其实不是。

data = {}print(type(data))

输出:

<class 'dict'>

空的大括号,在 Python 里默认表示空字典,不是空集合。

那空集合怎么写?

要用:

data = set()print(type(data))

输出:

<class 'set'>

所以这一点一定记住:

{} 是空字典set() 才是空集合

这是集合入门阶段最经典的坑之一。

五、集合里能放什么类型的数据

集合里的元素必须是不可变类型。

你现在先记最常见的结论就够了:

数字可以放 字符串可以放 元组通常可以放 列表不能放 字典不能放

比如下面这些都没问题:

s = {1, 2, 3, 'hello', 'python'}print(s)

但如果你这样写:

s = {1, 2, [3, 4]}

就会报错。

因为列表是可变的,不能作为集合元素。

你可以简单理解成:

集合要求每个元素都得是稳定的 如果一个东西自己还会变来变去,集合就不好管理它

初学阶段记住这条就够用了。

六、集合和列表,看着都能装多个值,到底差在哪

这个问题很关键。

列表和集合都能装多个元素,但设计目标完全不同。

列表更适合:

保留顺序 允许重复 按位置访问 需要频繁按索引处理数据

集合更适合:

去重 快速判断元素是否存在 不关心顺序 不需要按位置操作

看一个对比例子。

列表:

names = ['张三', '李四', '张三', '王五']print(names)

输出:

['张三', '李四', '张三', '王五']

重复的内容会原样保留。

集合:

names = {'张三', '李四', '张三', '王五'}print(names)

输出:

{'张三', '李四', '王五'}

重复项会自动消失。

所以到底选哪个,不是看谁语法酷,而是看你的数据需求是什么。

如果你要的是一份完整记录,包括重复项,那就用列表。 如果你只关心有哪些不同的值,那就用集合。

七、最常见的集合用途:给列表去重

这一招非常实用,也几乎是所有人学集合时最先用到的场景。

比如现在有一个列表:

names = ['张三', '李四', '张三', '王五', '李四']

我们想去掉重复项,可以直接转成集合:

names = ['张三', '李四', '张三', '王五', '李四']result = set(names)print(result)

输出:

{'张三', '李四', '王五'}

这就完成去重了。

不过你要注意,转成集合之后,结果是集合类型,不再是列表。

如果你最终还想要列表,可以再转回来:

names = ['张三', '李四', '张三', '王五', '李四']result = list(set(names))print(result)

这样就得到了一个去重后的列表。

这招在日常数据处理中非常常见。

比如:

ids = [101, 102, 101, 103, 102, 104]unique_ids = list(set(ids))print(unique_ids)

这就是最典型的批量去重思路。

不过这里要提醒一句:

用 set() 去重后,原来的顺序通常不会保留。

如果你既想去重,又特别在意原顺序,后面要用别的方法。 但在入门阶段,先把 set 去重这个核心能力掌握住最重要。

八、如何往集合里添加元素

集合没有 append(),因为那是列表的方法。

集合添加元素,用的是 add()。

s = {1, 2, 3}s.add(4)print(s)

输出:

{1, 2, 3, 4}

如果你添加的是一个已经存在的元素,会怎么样?

s = {1, 2, 3}s.add(2)print(s)

输出还是:

{1, 2, 3}

不会报错,也不会多出一个 2。

这再次说明,集合天然不允许重复。

你往里加一个已经有的东西,它就当没发生过。

这在很多业务场景里特别省事。 你不用自己先写 if 判断有没有重复,集合帮你处理掉了。

九、一次添加多个元素:update()

如果你一次想加入多个值,可以用 update()。

s = {1, 2, 3}s.update([3, 4, 5, 6])print(s)

输出:

{1, 2, 3, 4, 5, 6}

这里传进去的是一个列表,也可以是元组、集合等可迭代对象。

update() 会把里面的元素一个个拿出来,加入到原集合中。 重复的会自动忽略,不重复的会加进去。

这一点很像批量合并。

比如你有一批旧标签,又来了一批新标签:

tags = {'Python', '爬虫'}tags.update(['数据分析', 'Python', '自动化'])print(tags)

最后 Python 不会重复出现,集合会自动帮你合并成不重复的一组标签。

十、删除元素:remove() 和 discard()

集合删除元素时,常见有两个方法:

remove()discard()

先看 remove():

s = {1, 2, 3, 4}s.remove(3)print(s)

输出:

{1, 2, 4}

如果你删的是不存在的元素,会报错。

s.remove(10)

这就会出问题。

再看 discard():

s = {1, 2, 3, 4}s.discard(3)print(s)

一样能删除。

但如果删的是不存在的元素:

s.discard(10)

它不会报错,程序会安静地继续往下走。

所以这两个方法的区别可以这样记:

remove() 比较严格,删不到就报错discard() 比较温和,删不到也没事

在实际开发里,如果你不确定某个元素一定存在,discard() 会更稳一些。

十一、pop():随机删除一个元素

集合也有 pop(),但它和列表的 pop() 很不一样。

列表的 pop() 通常是按位置删。 集合没有位置概念,所以集合的 pop() 是随机拿走一个元素。

s = {1, 2, 3, 4}x = s.pop()print(x)print(s)

你会发现每次拿走的未必都一样。

因为集合本来就是无序的。 所以这个方法你知道有就行,入门阶段不用太依赖它做核心逻辑。

如果你明确想删某个指定元素,还是优先用 remove() 或 discard()。

十二、clear():清空整个集合

这一点和字典、列表的思路差不多。

s = {1, 2, 3}s.clear()print(s)

输出:

set()

集合还在,只是里面空了。

十三、判断某个元素在不在集合里

这又是集合特别强的一点。

看例子:

s = {'Python', 'Java', 'Go'}print('Python'in s)print('C++'in s)

输出:

TrueFalse

这个判断写法看起来和列表一样,但集合在这种场景下通常更高效。

也就是说:

如果你经常要做 某个值在不在 这种判断,集合往往比列表更合适。

比如用户名是否已存在:

users = {'tom', 'jerry', 'alice'}if'tom'in users:    print('用户名已存在')

比如某个商品编号是否出现过:

product_ids = {1001, 1002, 1003}if1002in product_ids:    print('找到了')

集合在这种快速查找场景里,非常好用。

十四、为什么说集合查重和判断存在特别高效

这一节不讲太深的底层原理,只讲你能听懂的版本。

列表判断某个元素在不在,很多时候得从前往后一个个看。

比如你问:

这个值在列表里吗

程序通常要看第一个、第二个、第三个……慢慢找。

但集合不是这么干的。 它天生就为 快速判断某个元素是否存在 设计了更适合的结构。

所以当数据量变大时,这种差距会越来越明显。

你可以先把它理解成:

列表更像排队找人 集合更像查名册

排队一个个看,当然慢一点。 查名册直接定位,通常更快。

所以集合的关键词,不只是 去重,还有 快速查找。

十五、遍历集合

集合当然也可以遍历。

s = {'Python', 'Java', 'Go'}for item in s:    print(item)

这没问题。

但你要记住,因为集合无序,所以遍历出来的顺序不一定固定。

如果你的逻辑特别依赖顺序,那集合可能就不适合你。

这一点非常重要。

比如你要输出排行榜、打印成绩单、按先后顺序展示数据,那就不要指望集合。 集合不是干这个的。

它更适合做 去重、筛选、判断存在 这些事情。

十六、集合之间的运算,才是它真正厉害的地方

前面那些去重、添加、删除,已经很实用了。 但集合还有一类特别经典的操作:

集合和集合之间做运算

比如两批用户,找共同关注的人。 两组标签,找重合部分。 两个班级名单,找交集、并集、差集。

这时候,集合会非常顺手。

十七、交集:两边都有的内容

交集,就是两个集合共同拥有的元素。

a = {1, 2, 3, 4}b = {3, 4, 5, 6}print(a & b)print(a.intersection(b))

输出:

{3, 4}{3, 4}

这表示 3 和 4 同时出现在两个集合里。

现实里很容易理解。

比如:

A 班报名名单 B 班报名名单 想找两个班都报名了的人

这就是交集。

十八、并集:把两边所有元素合在一起并去重

并集,就是两个集合所有元素合起来,重复的只保留一份。

a = {1, 2, 3}b = {3, 4, 5}print(a | b)print(a.union(b))

输出:

{1, 2, 3, 4, 5}{1, 2, 3, 4, 5}

这个特别适合合并标签、合并名单、合并编号集合。

比如一份老客户名单和一份新客户名单,你想得到全部客户,并且不重复,就很适合并集。

十九、差集:只在一边出现,在另一边没有

差集,就是找出只属于其中一边的元素。

a = {1, 2, 3, 4}b = {3, 4, 5}print(a - b)print(a.difference(b))

输出:

{1, 2}{1, 2}

表示在 a 里有,但在 b 里没有的元素。

这个思路在业务里很常见。

比如:

昨天的用户集合 今天的用户集合 想找今天新增了哪些用户

或者:

系统允许访问的权限集合 用户实际拥有的权限集合 想找还缺哪些权限

差集就派上用场了。

二十、对称差集:只保留不重合的部分

这个名字听起来有点拗口,但意思不难。

a = {1, 2, 3, 4}b = {3, 4, 5, 6}print(a ^ b)print(a.symmetric_difference(b))

输出:

{1, 2, 5, 6}{1, 2, 5, 6}

也就是:

去掉共同部分 只保留各自独有的部分

你现在不一定会马上用到,但知道有这个能力就够了。 等以后处理两批数据差异时,会很有用。

二十一、一个特别贴近实际的小案例:网站访问去重

假设你拿到一批访问用户名单:

visits = ['tom', 'jerry', 'tom', 'alice', 'bob', 'alice', 'tom']

现在你想知道:

一共有多少个不同用户来过 分别是谁

代码可以这样写:

visits = ['tom', 'jerry', 'tom', 'alice', 'bob', 'alice', 'tom']user_set = set(visits)print('去重后用户集合:', user_set)print('独立用户数:', len(user_set))

这样一下就出来了。

如果不用集合,你得写循环、写判断、手动维护去重逻辑。 而集合直接把问题简化了。

这就是 Python 容器类型真正迷人的地方:

合适的工具一选对,很多问题一下就轻了。

二十二、再看一个场景:共同好友

假设小明的好友有:

friends_a = {'张三', '李四', '王五', '赵六'}

小红的好友有:

friends_b = {'王五', '赵六', '小刚'}

想找共同好友:

friends_a = {'张三', '李四', '王五', '赵六'}friends_b = {'王五', '赵六', '小刚'}common = friends_a & friends_bprint(common)

输出:

{'王五', '赵六'}

如果不用集合,这种问题会写得麻烦很多。 但集合一上来,思路就特别自然。

二十三、集合最容易犯的几个错

先说第一个,也是最经典的。

很多人写空集合时,写成:

s = {}

这其实是字典,不是集合。

第二个坑,是把集合当列表用,想按索引取值:

s = {1, 2, 3}print(s[0])

这不行,因为集合无序,没有索引。

第三个坑,是往集合里放列表:

s = {1, 2, [3, 4]}

这会报错,因为列表不能作为集合元素。

第四个坑,是以为 set 去重后还能保留原顺序。 大多数情况下不能指望这一点。

第五个坑,是分不清 remove() 和 discard()。 一个删不到会报错,一个删不到也没事。

这些坑你现在提前知道,后面写代码时就能少踩很多雷。

二十四、集合和字典,看着都像大括号,怎么快速分辨

这一点值得再强调一次。

字典:

{'name': '张三', 'age': 18}

特征是里面有冒号,有键和值。

集合:

{'张三', '李四', '王五'}

特征是里面只有值,没有冒号。

再补一个细节:

空字典是 {}空集合是 set()

这个区别,新手一定要牢牢记住。

二十五、什么时候该用集合

这里给你一个最实用的判断标准。

如果你遇到下面这些需求,优先考虑集合:

需要去重 需要快速判断某个值在不在 需要比较两批数据有没有重合 需要找共同部分、不同部分 不在意元素顺序

比如:

用户名是否重复 商品标签去重 统计不同访问用户 找两个班级的共同学生 找两份名单的差异

这些都非常适合集合。

二十六、什么时候不该用集合

反过来,如果你特别在意下面这些事,就别轻易用集合:

需要保留顺序 允许重复 需要按位置访问 需要切片 需要记录每个值出现了几次

比如成绩单、购物车顺序、聊天消息列表,这些更适合列表。 集合不是万能容器,它只是特别擅长某些问题。

真正会写代码的人,不是见什么都用一种结构,而是能根据问题选对结构。

二十七、练习题:把集合真正用起来

下面这些小练习,建议你自己敲一遍。

1. 定义一个集合,包含 1、2、3、4

s = {1, 2, 3, 4}print(s)

2. 把列表去重

nums = [1, 2, 2, 3, 4, 4, 5]result = set(nums)print(result)

3. 给集合添加一个新元素 6

s = {1, 2, 3}s.add(6)print(s)

4. 删除集合中的 2

s = {1, 2, 3, 4}s.remove(2)print(s)

5. 判断 3 是否在集合中

s = {1, 2, 3, 4}print(3in s)

6. 求两个集合的交集

a = {1, 2, 3, 4}b = {3, 4, 5, 6}print(a & b)

7. 求两个集合的并集

print(a | b)

8. 求两个集合的差集

print(a - b)

你把这些题自己敲一遍,集合最核心的感觉就基本建立起来了。

二十八、本章小结

这一章你最需要记住的,不是 set 这个单词,而是集合背后的用途。

集合是一种不重复、无序的数据容器。 它最擅长两件事:

去重 快速判断某个元素是否存在

你要记住的核心点有这些:

集合里的元素不能重复 集合没有索引,不能按位置取值 空集合要用 set() 创建 添加元素用 add()删除元素常用 remove() 或 discard()集合特别适合做交集、并集、差集运算

如果说列表是拿来装一排数据的, 字典是拿来描述一条信息的, 那集合更像一个筛子。

它会帮你把重复的滤掉,把重合的找出来,把差异的挑出来。

下一章我们继续讲 列表、元组、字典、集合,到底该怎么选。 到那一章,前面这些容器类型就会真正串起来,你会慢慢建立一种看见问题就知道该用什么数据结构的感觉。

最新文章

随机文章