去除列表中的重复项

1468 投票
58 回答
2158804 浏览
提问于 2025-04-17 05:23

我该怎么检查一个列表里有没有重复的元素,并返回一个没有重复元素的新列表呢?

58 个回答

216

这是一行代码就能解决的问题:list(set(source_list)) 就可以搞定。

这里的 set 是一种数据结构,它的特点是不能有重复的元素。

更新一下:如果想保持顺序,可以用两行代码:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

在这里,我们利用了 OrderedDict 这个特性,它会记住键的插入顺序,并且在更新某个键的值时不会改变这个顺序。我们把 True 作为值插入,但其实可以插入任何东西,值在这里并不重要。(set 的工作方式也很像 dict,只是值会被忽略。)

485

在 Python 2.7 中,去掉可迭代对象中的重复项,同时保持原来的顺序的新方法是:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在 Python 3.5 中,OrderedDict 有了 C 语言的实现。我的测试显示,这种方法现在是 Python 3.5 中最快和最简短的去重方式。

在 Python 3.6 中,普通的字典变得既有序又紧凑。(这个特性在 CPython 和 PyPy 中是有效的,但在其他实现中可能不适用。)这给我们提供了一种新的最快的去重方法,同时保持顺序:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']

在 Python 3.7 中,普通字典在所有实现中都保证是有序的。所以,最简短和最快的解决方案是:

>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
2262

想要得到一组独特的物品,常用的方法是使用set。集合是一种无序的、包含不同对象的集合。你可以通过把任何可迭代的对象传给内置的set()函数来创建一个集合。如果你之后需要一个真正的列表,可以同样把集合传给list()函数。

下面的例子应该能帮助你理解你想做的事情:

>>> t = [1, 2, 3, 1, 2, 3, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

从例子的结果可以看到,原来的顺序没有被保留。正如上面提到的,集合本身就是无序的,所以顺序会丢失。当你把集合转换回列表时,会产生一个任意的顺序。

保持顺序

如果顺序对你来说很重要,那么你需要使用不同的方法。一个常见的解决方案是使用OrderedDict来在插入时保持键的顺序:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

从Python 3.7开始,内置字典也保证会保持插入顺序,所以如果你使用的是Python 3.7或更高版本(或者CPython 3.6),你也可以直接使用字典:

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

需要注意的是,这可能会有一些额外的开销,因为你需要先创建一个字典,然后再从中创建一个列表。如果你不需要保持顺序,通常使用集合会更好,特别是因为集合提供了更多的操作方式。想了解更多细节和去重时保持顺序的其他方法,可以查看这个问题


最后要注意的是,setOrderedDict/dict的解决方案都要求你的项目是可哈希的。这通常意味着它们必须是不可变的。如果你需要处理不可哈希的项目(例如列表对象),那么你将不得不使用一种较慢的方法,基本上需要在嵌套循环中比较每个项目与其他每个项目。

撰写回答