Python 列表怎么去重?附 4 种方法详解(set、推导式、循环、字典)

编程狮(w3cschool.cn) 2026-08-05 15:29:47 浏览数 (81)
反馈

你手里有一个 Python 列表,里面混进了重复元素:用户 ID 重复了、爬来的数据有脏记录、或者循环里多 append 了几次。你只想"把重复的去掉,只留一份",却卡在"到底用哪种写法"。直接给答案:Python 列表去重最快的是用 set 集合(一行搞定,但不保序);想保留原顺序,用"列表推导式 + 辅助集合";想完全看清每一步,用 for 循环;既要保序又想顺带统计次数,用字典。今天这篇文章,编程狮把四种 Python 列表去重方法从原理到代码讲透,并附上该选哪种的实用建议。

一、为什么列表会重复,去重要先想清两件事

列表(list)是 Python 里最常用的容器,它允许重复元素、保持插入顺序。重复往往来自三处:数据采集时的脏记录、多次 append 或 extend、以及不同来源的合并。在写 Python 列表去重代码前,先想清两件事:第一,要不要保留原来的先后顺序?第二,重复项出现多次时,要不要顺便知道"它出现了几次"?这两个问题直接决定你该用下面四种方法里的哪一种。先确认基础概念:列表用方括号 [] 定义,元素之间用逗号隔开,同一个值可以出现任意多次。正因为这种"允许重复"的特性,去重才成了日常最高频的小需求之一——从清洗爬虫结果、合并用户标签,到统计日志里的独立访问,几乎每个数据处理脚本都会碰到。从速度看,set 去重是 O(n) 且由 C 实现,最快;推导式与循环同是 O(n) 但走 Python 层,略慢;字典法因为要维护计数,开销稍大——日常数据量下这点差别基本无感,选可读性更高的写法就行。

二、方法一:用 set 集合最快去重(不保序)

set 是 Python 里的"集合"类型,它的天性就是"只存不重复的元素"。把列表丢进 set(),重复项会被自动合并,再转回 list 就得到去重结果。

nums = [1, 2, 2, 3, 3, 3, 1]
unique = list(set(nums))
print(unique)  # 结果可能是 [1, 2, 3](顺序不保证)

这段做的是:set(nums) 把列表变成一个集合,重复的 1、2、3 各只剩一份;list(...) 再把它变回列表。它的优点是写法最短、速度最快,适合"只要唯一值、不在乎顺序"的场景,比如去重标签、去重 ID。代价是 set 不保证顺序——每次运行结果顺序可能不同。还要注意,set 只接受"可哈希"的元素,像列表、字典这种本身可变的类型不能放进 set,碰到它们得先转成元组或字符串再处理,否则会直接报错。如果你刚接触 Python,建议先过一遍 Python3 教程 里的容器章节,把列表和集合的关系打牢,后面三种方法都建立在它之上。

三、方法二:列表推导式 + 辅助集合,保序去重

很多业务里顺序很重要(比如按时间采集的日志、按出现先后展示的列表),这时候就要"保序去重"。做法是用一个空集合记住"已经见过哪些元素",遍历原列表时,只在没见过时才收进新列表。

nums = [1, 2, 2, 3, 3, 3, 1]
seen = set()
unique = [x for x in nums if not (x in seen or seen.add(x))]
print(unique)  # [1, 2, 3],顺序与首次出现一致

这里用了列表推导式:对 nums 里每个 x,如果它不在 seen 里,就收进结果,同时 seen.add(x) 把它记下来。seen.add(x) 永远返回 None,所以 "x in seen or seen.add(x)" 在首次遇到 x 时为 False,元素被保留。它既保序,又只多花一点点代码,是日常最常用的 Python 列表去重一招。这套写法时间复杂度是 O(n),每个元素只判断一次,对几万条数据也毫无压力。常忘语法的同学,Python 速查手册 可以贴在旁边随时翻。

四、方法三:for 循环手动去重,逻辑最透明

如果你更希望"每一步都看得见",用最朴素的 for 循环最稳妥,也最适合初学者理解去重的本质。

nums = [1, 2, 2, 3, 3, 3, 1]
seen = set()
unique = []
for x in nums:
    if x not in seen:
        seen.add(x)
        unique.append(x)
print(unique)  # [1, 2, 3]

这段和上一节的推导式是同一套思路,只是把判断和添加拆成了更直白的几行:遇到没见过的 x,先记进 seen,再 append 到结果。它比推导式啰嗦,但调试时你能清楚看到每一步,改起来也直观。当你要在去重的同时做别的事(比如顺便打印日志、过滤特定值),循环是最灵活的底子。初学者最容易在这里建立直觉:所谓"去重",本质上就是"见过就跳过",循环把这件事摊开给你看,以后再遇见"只取第一次出现"这类需求,套路都一样。理解了这个循环,前面那行推导式也就不再神秘。

五、方法四:用字典去重并顺带计数

有时候你不但要去重,还想知道"每个元素出现了几次"。Python 3.7 之后,字典(dict)会保持插入顺序,于是可以一边去重一边计数。

nums = [1, 2, 2, 3, 3, 3, 1]
count = {}
for x in nums:
    count[x] = count.get(x, 0) + 1
unique = list(count.keys())
print(unique)    # [1, 2, 3],保序
print(count)     # {1: 2, 2: 2, 3: 3}

这段做的是:遍历 nums,用 count.get(x, 0) 取出 x 已有的次数(没有就当 0),加一后写回;最后字典的键天然不重复且保序,list(count.keys()) 就是去重后的列表,count 本身还是一份频率统计。count.get(x, 0) 里的 0 是默认值,第一次见到 x 时返回 0,加一后变成 1;等第二次见到就累加成了 2。这个"默认值 + 自增"的写法,是统计频次最通用的模板。需要"去重 + 计数"二合一时,这招最省事。想系统背熟这类 Python 内置用法,编程词典 里的速查表能帮你随时定位。

六、总结:四种 Python 列表去重方法怎么选

一句话收束:Python 列表去重没有唯一正解,只有最合场景的那一种。

  • 只要唯一值、不在乎顺序 → 直接用 set,一行最爽;
  • 要保留原顺序 → 列表推导式 + 辅助集合,日常首选;
  • 想看清每一步、顺便加逻辑 → for 循环,最透明;
  • 去重还要计数 → 字典,二合一。

补充一点:这四种都只处理"完全相等"的重复。如果你的列表里是字典或对象,得先定好"什么算重复"(比如按某个字段),再套上面的思路。另外提醒,去重不等于排序——四种方法都不会帮你从小到大排好,如果既要去重又要排序,记得最后再套一层 sorted()。下次再遇到 Python 列表去重,先问自己"保不保序、计不计次",方法立刻就定了,不必每次都现搜。

延伸学习

想把 Python 列表和容器玩明白,可以按这个顺序:

  1. 先把列表、集合、字典三种容器的区别吃透,这是去重的地基;
  2. 常忘语法时翻 Python 开发方向 给出的体系地图,找对下一步学什么;
  3. 想系统入门并动手练,Python 零基础到高薪就业 是边学边写的形式,适合打牢基础。

常见问题

Q:set 去重后顺序乱了,怎么既快又保序? A:用"列表推导式 + 辅助集合"或字典法,二者都保序,速度也接近 set,是保序场景的推荐写法。

Q:列表里是字典,怎么按某个字段去重? A:先用一个集合记录"见过的字段值",再用推导式或循环筛掉重复字段的行,思路和本文一致,只是判断条件换成那个字段。

Q:去重后的列表能和原列表比较长度吗? A:可以,len(原列表) - len(去重后) 就是被去掉的重复项数量,常用来快速判断数据里有多少脏重复。

0 人点赞