删除列表中的重复项
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了删除列表中的重复项相关的知识,希望对你有一定的参考价值。
几乎我需要编写一个程序来检查列表是否有任何重复项,如果有,它会删除它们并返回一个新列表,其中包含未重复/删除的项目。这就是我所拥有的,但说实话,我不知道该怎么做。
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
获得一个独特的项目集合的常用方法是使用set
。集合是不同对象的无序集合。要从任何可迭代创建集合,您只需将其传递给内置的set()
函数即可。如果您以后再次需要一个真实的列表,您可以类似地将该集合传递给list()
函数。
以下示例应涵盖您尝试执行的操作:
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 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]
从示例结果中可以看出,未维护原始订单。如上所述,集合本身是无序集合,因此订单丢失。将集合转换回列表时,会创建任意顺序。
Maintaining order
如果订单对您很重要,那么您将不得不使用不同的机制。一个非常常见的解决方案是依靠OrderedDict
在插入过程中保持键的顺序:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Starting with Python 3.7,内置字典也保证维护插入顺序,因此如果您使用的是Python 3.7或更高版本(或CPython 3.6),也可以直接使用它:
>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
请注意,这会产生首先创建字典,然后从中创建列表的开销。如果您实际上不需要保留订单,那么最好使用一套。查看this question以获取更多详细信息以及删除重复项时保留订单的其他方法。
最后请注意,set
以及OrderedDict
/ dict
解决方案都要求您的物品可以清洗。这通常意味着它们必须是不可变的。如果你必须处理不可清除的项目(例如列表对象),那么你将不得不使用一种缓慢的方法,在这种方法中你基本上必须将每个项目与嵌套循环中的每个其他项目进行比较。
简单易用:
myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]
输出:
>>> cleanlist
[1, 2, 3, 5, 6, 7, 8]
我的名单中有一个词典,所以我无法使用上述方法。我收到了错误:
TypeError: unhashable type:
因此,如果您关心订单和/或某些商品是不可取消的。然后你可能会觉得这很有用:
def make_unique(original_list):
unique_list = []
[unique_list.append(obj) for obj in original_list if obj not in unique_list]
return unique_list
有些人可能认为列表理解有副作用,不是一个好的解决方案。这是另一种选择:
def make_unique(original_list):
unique_list = []
map(lambda x: unique_list.append(x) if (x not in unique_list) else False, original_list)
return unique_list
到目前为止,我在这里看到的所有顺序保留方法都使用了天真的比较(最好是O(n ^ 2)时间复杂度)或者是限于可输入输入的重量级OrderedDicts
/ set
+ list
组合。这是一个独立于哈希的O(nlogn)解决方案:
Update添加了key
参数,文档和Python 3兼容性。
# from functools import reduce <-- add this import on Python 3
def uniq(iterable, key=lambda x: x):
"""
Remove duplicates from an iterable. Preserves order.
:type iterable: Iterable[Ord => A]
:param iterable: an iterable of objects of any orderable type
:type key: Callable[A] -> (Ord => B)
:param key: optional argument; by default an item (A) is discarded
if another item (B), such that A == B, has already been encountered and taken.
If you provide a key, this condition changes to key(A) == key(B); the callable
must return orderable objects.
"""
# Enumerate the list to restore order lately; reduce the sorted list; restore order
def append_unique(acc, item):
return acc if key(acc[-1][1]) == key(item[1]) else acc.append(item) or acc
srt_enum = sorted(enumerate(iterable), key=lambda item: key(item[1]))
return [item[1] for item in sorted(reduce(append_unique, srt_enum, [srt_enum[0]]))]
尝试使用套装:
import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])
print t | t1
print t - t1
你也可以这样做:
>>> t = [1, 2, 3, 3, 2, 4, 5, 6]
>>> s = [x for i, x in enumerate(t) if i == t.index(x)]
>>> s
[1, 2, 3, 4, 5, 6]
上述原因是index
方法只返回元素的第一个索引。重复元素具有更高的索引。请参阅here:
list.index(x [,start [,end]]) 在值为x的第一个项的列表中返回从零开始的索引。如果没有这样的项,则引发ValueError。
通过订购保留减少变量:
假设我们有列表:
l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
减少变量(效率低):
>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]
5倍速但更复杂
>>> reduce(lambda r, v: v in r[1] and r or (r[0].append(v) or r[1].add(v)) or r, l, ([], set()))[0]
[5, 6, 1, 2, 3, 4]
说明:
default = (list(), set())
# user list to keep order
# use set to make lookup faster
def reducer(result, item):
if item not in result[1]:
result[0].append(item)
result[1].add(item)
return result
reduce(reducer, l, default)[0]
从列表中删除重复项的最佳方法是使用python中提供的set()函数,再次将该集转换为列表
In [2]: some_list = ['a','a','v','v','v','c','c','d']
In [3]: list(set(some_list))
Out[3]: ['a', 'c', 'd', 'v']
您可以使用以下功能:
def rem_dupes(dup_list):
yooneeks = []
for elem in dup_list:
if elem not in yooneeks:
yooneeks.append(elem)
return yooneeks
例:
my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
用法:
rem_dupes(my_list)
['this','is','a','list','with','duplicates','in','the']
如果您想保留订单,而不是使用任何外部模块,这是一种简单的方法:
>>> t = [1, 9, 2, 3, 4, 5, 3, 6, 7, 5, 8, 9]
>>> list(dict.fromkeys(t))
[1, 9, 2, 3, 4, 5, 6, 7, 8]
注意:此方法保留了外观的顺序,因此,如上所示,九个将在一个之后,因为它是第一次出现。然而,这与您所做的结果相同
from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))
但它更短,运行速度更快。
这是有效的,因为每次fromkeys
函数尝试创建一个新键时,如果该值已经存在,它将只是覆盖它。然而,这根本不会影响字典,因为fromkeys
创建了一个字典,其中所有键都具有值None
,因此它有效地以这种方式消除了所有重复。
还有许多其他答案提出了不同的方法来做到这一点,但它们都是批处理操作,其中一些抛弃了原始订单。这可能是好的,具体取决于你需要什么,但如果你想按照每个值的第一个实例的顺序迭代值,并且你想要一次性删除重复项,你可以使用这个发电机:
def uniqify(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
这将返回一个生成器/迭代器,因此您可以在任何可以使用迭代器的地方使用它。
for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
print(unique_item, end=' ')
print()
输出:
1 2 3 4 5 6 7 8
如果你想要一个list
,你可以这样做:
unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))
print(unique_list)
输出:
[1, 2, 3, 4, 5, 6, 7, 8]
在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中,常规字典变得有序且紧凑。
以上是关于删除列表中的重复项的主要内容,如果未能解决你的问题,请参考以下文章