学径 LearnPath

编程语言基础 / Wiki

集合

一堆互不重复、也不讲究次序的值;用来判断属于不属于,以及做交并差。

它是什么

集合 来自数学:一堆对象,每个只出现一次,成员之间没有「第几个」的说法。Python 的集合适合去重、判断属于不属于、做交并差。加入已有的元素,集合大小不变——这不是丢失数据的故障,而是这份结构对「同一性」的承诺。

python
seen = {3, 1, 3, 2}
print(seen)          # 3 只保留一次
print(2 in seen)

空集合不能写成 {},那是空 字典。空集合要写 set()。数学课上的集合可以是无限的;程序里的集合必须装得下,是有限的那一种。

名字从哪来

set 就是集合论里的集合。康托尔在 19 世纪末把「一组对象」做成严格的数学对象。编程语言把这套运算搬进来:并 |、交 &、差 -,和数学教材里的符号对应。集合内部通常也用散列,所以元素必须可哈希,规则和字典的键类似:列表 不能放进集合。需要装复合对象时,改用 元组。

它怎么工作

in 测试成员关系,平均很快。遍历集合时不要依赖某一种固定次序;打印时有时看起来像排过,那不是保证。需要次序时,先变成列表再排序。从列表构造 set(items) 是去重的常用写法。去重之后若还要保持原顺序,集合单独做不到,得另外处理。

「在或不在」是集合提供的模型。若问题真正关心的是第几次出现、或键所对应的值,就不该用集合去勉强表达。选择容器,就是选择允许哪些问题被问出来。

生活里在哪里

到过的城市:去过就是去过,不记第几次。抽奖箱里的唯一号码。两个班级名单求「都参加了」的人,就是交集。流行病学里的「曾暴露 / 未暴露」,户籍里的「是否登记」,都更接近集合而不是有序清单。把这些写成列表并手工去重,可以做出相似的结果,却把「唯一性」从结构里拿出来,变成一串容易漏写的步骤。

和相近概念的差别

列表保留重复和次序。字典保留键值对。集合只有「在或不在」。元组有次序且结构不可变,但仍允许重复;集合既不保证次序,也不保留重复。

与选择、循环的差别在于:集合是数据的组织方式,不是控制流。可以在 循环 里把元素加入集合,从而记录「已经见过」;那是用集合为循环提供记忆,而不是集合本身在重复执行步骤。

常见误会

误会 1:{} 是空集合。

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

误会 2:集合会按从小到大排好。

打印时有时看起来像排过,那不是保证。要顺序,自己排序。

误会 3:把可变的列表放进集合。

会报错。需要装复合对象时,改用元组。

想知道更多

  • 书:艾伦·唐尼《像计算机科学家一样思考Python(第2版)》
  • 书:布鲁克希尔《计算机科学概论》
  • 书:埃里克·马瑟斯《Python编程:从入门到实践(第3版)》

未登录时不会保存学习进度