Nee*_*imo 883 python algorithm intersection list duplicates
几乎我需要编写一个程序来检查列表是否有任何重复项,如果有,它会删除它们并返回一个新列表,其中包含未复制/删除的项目.这就是我所拥有的,但说实话,我不知道该怎么做.
def remove_duplicates():
t = ['a', 'b', 'c', 'd']
t2 = ['a', 'c', 'd']
for t in t2:
t.append(t.remove())
return t
Run Code Online (Sandbox Code Playgroud)
pok*_*oke 1477
获取唯一项目集合的常用方法是使用a 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]
Run Code Online (Sandbox Code Playgroud)
从示例结果中可以看出,未维护原始订单.如上所述,集合本身是无序集合,因此订单丢失.将集合转换回列表时,会创建任意顺序.
如果订单对您很重要,那么您将不得不使用不同的机制.一个非常常见的解决方案是依赖于OrderedDict在插入过程中保持键的顺序:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]
Run Code Online (Sandbox Code Playgroud)
请注意,这会产生首先创建字典,然后从中创建列表的开销.因此,如果您实际上不需要保留订单,那么最好使用一套.查看此问题以获取更多详细信息以及删除重复项时保留订单的其他方法.
最后请注意,无论是set还有OrderedDict的解决方案需要您的项目是哈希的.这通常意味着它们必须是不可变的.如果你必须处理不可清除的项目(例如列表对象),那么你将不得不使用一种缓慢的方法,在这种方法中你基本上必须将每个项目与嵌套循环中的每个其他项目进行比较.
Ray*_*ger 386
在Python 2.7中,从迭代中删除重复项同时保持原始顺序的新方法是:
>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Run Code Online (Sandbox Code Playgroud)
在Python 3.5中,OrderedDict有一个C实现.我的时间表明,现在这是Python 3.5的各种方法中最快和最短的.
在Python 3.6中,常规字典变得有序且紧凑.(此功能适用于CPython和PyPy,但在其他实现中可能不存在).这为我们提供了一种新的最快的扣除方式,同时保留了订单:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Run Code Online (Sandbox Code Playgroud)
在Python 3.7中,保证常规字典在所有实现中都有序. 因此,最短和最快的解决方案是:
>>> list(dict.fromkeys('abracadabra'))
['a', 'b', 'r', 'c', 'd']
Run Code Online (Sandbox Code Playgroud)
900*_*000 180
这是一个单线:list(set(source_list))将做的伎俩.
A set是不可能有重复的东西.
更新:订单保留方法有两行:
from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()
Run Code Online (Sandbox Code Playgroud)
这里我们使用OrderedDict记住键的插入顺序的事实,并且在更新特定键的值时不更改它.我们插入True值作为值,但我们可以插入任何内容,只是不使用值.(也set可以像dict忽略值那样工作.)
小智 87
>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> s = []
>>> for i in t:
if i not in s:
s.append(i)
>>> s
[1, 2, 3, 5, 6, 7, 8]
Run Code Online (Sandbox Code Playgroud)
Rei*_*ica 79
如果您不关心订单,请执行以下操作:
def remove_duplicates(l):
return list(set(l))
Run Code Online (Sandbox Code Playgroud)
A set保证不会有重复.
小智 37
创建一个新列表,保留重复项的第一个元素的顺序 L
newlist=[ii for n,ii in enumerate(L) if ii not in L[:n]]
例如,if L=[1, 2, 2, 3, 4, 2, 4, 3, 5]那newlist将是[1,2,3,4,5]
这会在添加之前检查先前未在列表中出现的每个新元素.它也不需要进口.
Cor*_*man 25
在这个答案中,将有两个部分:两个独特的解决方案,以及特定解决方案的速度图。
这些答案中的大多数只删除了可散列的重复项,但这个问题并不意味着它不仅需要可散列的项目,这意味着我将提供一些不需要可散列项的解决方案。
collections.Counter是标准库中的一个强大工具,可以完美地解决这个问题。只有另一种解决方案甚至包含 Counter 。但是,该解决方案也仅限于可散列的键。
为了在 Counter 中允许不可散列的键,我创建了一个 Container 类,它将尝试获取对象的默认散列函数,但如果失败,它将尝试其标识函数。它还定义了一个eq和一个哈希方法。这应该足以在我们的解决方案中允许不可散列的项目。不可散列对象将被视为可散列对象。然而,这个散列函数对不可散列的对象使用标识,这意味着两个均不可散列的相等对象将不起作用。我建议您覆盖它,并将其更改为使用等效可变类型的哈希(例如使用hash(tuple(my_list))ifmy_list是列表)。
我也做了两个解决方案。另一种保持项目顺序的解决方案,使用名为“OrderedCounter”的 OrderedDict 和 Counter 的子类。现在,这里是功能:
from collections import OrderedDict, Counter
class Container:
def __init__(self, obj):
self.obj = obj
def __eq__(self, obj):
return self.obj == obj
def __hash__(self):
try:
return hash(self.obj)
except:
return id(self.obj)
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first encountered'
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
def remd(sequence):
cnt = Counter()
for x in sequence:
cnt[Container(x)] += 1
return [item.obj for item in cnt]
def oremd(sequence):
cnt = OrderedCounter()
for x in sequence:
cnt[Container(x)] += 1
return [item.obj for item in cnt]
Run Code Online (Sandbox Code Playgroud)
remd是无序排序,而oremd有序排序。您可以清楚地分辨出哪个更快,但无论如何我都会解释。无序排序稍微快一点,因为它不存储项目的顺序。
现在,我还想展示每个答案的速度比较。所以,我现在就这样做。
为了删除重复项,我从几个答案中收集了 10 个函数。我计算了每个函数的速度,并使用matplotlib.pyplot将其放入图形中。
我将其分为三轮绘图。可散列是任何可以散列的对象,不可散列是任何不能散列的对象。有序序列是保持顺序的序列,无序序列不保持顺序。现在,这里还有一些术语:
Unordered Hashable适用于任何删除重复项的方法,这些方法不一定要保持顺序。它不必对不可散列的人起作用,但它可以。
Ordered Hashable适用于任何保持列表中项目顺序的方法,但它不一定适用于不可散列的项目,但它可以。
Ordered Unhashable是任何保持列表中项目顺序的方法,并且适用于 unhashable。
在 y 轴上是它花费的秒数。
x 轴是应用函数的数字。
我使用以下理解为无序散列和有序散列生成了序列: [list(range(x)) + list(range(x)) for x in range(0, 1000, 10)]
对于有序的不可哈希的: [[list(range(y)) + list(range(y)) for y in range(x)] for x in range(0, 1000, 10)]
请注意step,范围内有一个,因为没有它,这将花费 10 倍的时间。也因为在我个人看来,我认为它可能看起来更容易阅读。
还要注意图例上的键是我试图猜测的函数实现中最重要的部分。至于哪个功能最差或最好?该图不言自明。
解决了这个问题,这里是图表。
vol*_*ano 23
一位同事已将接受的答案作为其代码的一部分发送给我,以便我今天进行代码审查.虽然我当然钦佩有问题的答案的优雅,但我对表现并不满意.我试过这个解决方案(我用set来减少查找时间)
def ordered_set(in_list):
out_list = []
added = set()
for val in in_list:
if not val in added:
out_list.append(val)
added.add(val)
return out_list
Run Code Online (Sandbox Code Playgroud)
为了比较效率,我使用了100个整数的随机样本--62个是唯一的
from random import randint
x = [randint(0,100) for _ in xrange(100)]
In [131]: len(set(x))
Out[131]: 62
Run Code Online (Sandbox Code Playgroud)
以下是测量结果
In [129]: %timeit list(OrderedDict.fromkeys(x))
10000 loops, best of 3: 86.4 us per loop
In [130]: %timeit ordered_set(x)
100000 loops, best of 3: 15.1 us per loop
Run Code Online (Sandbox Code Playgroud)
那么,如果从解决方案中删除了set,会发生什么?
def ordered_set(inlist):
out_list = []
for val in inlist:
if not val in out_list:
out_list.append(val)
return out_list
Run Code Online (Sandbox Code Playgroud)
结果没有OrderedDict那么糟糕,但仍然是原始解决方案的3倍多
In [136]: %timeit ordered_set(x)
10000 loops, best of 3: 52.6 us per loop
Run Code Online (Sandbox Code Playgroud)
Jam*_*pam 20
另一种做法:
>>> seq = [1,2,3,'a', 'a', 1,2]
>> dict.fromkeys(seq).keys()
['a', 1, 2, 3]
Run Code Online (Sandbox Code Playgroud)
G M*_*G M 20
还有使用Pandas和Numpy的解决方案.它们都返回numpy数组,因此.tolist()如果需要列表,则必须使用该函数.
t=['a','a','b','b','b','c','c','c']
t2= ['c','c','b','b','b','a','a','a']
Run Code Online (Sandbox Code Playgroud)
使用Pandas功能unique():
import pandas as pd
pd.unique(t).tolist()
>>>['a','b','c']
pd.unique(t2).tolist()
>>>['c','b','a']
Run Code Online (Sandbox Code Playgroud)
使用numpy功能unique().
import numpy as np
np.unique(t).tolist()
>>>['a','b','c']
np.unique(t2).tolist()
>>>['a','b','c']
Run Code Online (Sandbox Code Playgroud)
请注意,numpy.unique()也会对值进行排序.因此列表t2返回排序.如果您希望保留订单,请使用此答案:
_, idx = np.unique(t2, return_index=True)
t2[np.sort(idx)].tolist()
>>>['c','b','a']
Run Code Online (Sandbox Code Playgroud)
与其他解决方案相比,解决方案并不那么优雅,但与pandas.unique()相比,numpy.unique()还允许您检查嵌套数组是否沿一个选定的轴是唯一的.
Nim*_*ush 16
简单易用:
myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanlist = []
[cleanlist.append(x) for x in myList if x not in cleanlist]
Run Code Online (Sandbox Code Playgroud)
输出:
>>> cleanlist
[1, 2, 3, 5, 6, 7, 8]
Run Code Online (Sandbox Code Playgroud)
Nic*_*mer 13
我将各种建议与perfplot进行了比较。事实证明,如果输入数组没有重复元素,则所有方法都或多或少同样快,无论输入数据是 Python 列表还是 NumPy 数组。
如果输入数组很大,但仅包含一个唯一元素,并且输入数据是列表,set则、dict和np.unique方法是常量时间的。如果它是 NumPy 数组,则比其他替代方案快大约 10 倍。np.unique
让我有些惊讶的是,这些操作也不是恒定时间的。
重现绘图的代码:
import perfplot
import numpy as np
import matplotlib.pyplot as plt
def setup_list(n):
# return list(np.random.permutation(np.arange(n)))
return [0] * n
def setup_np_array(n):
# return np.random.permutation(np.arange(n))
return np.zeros(n, dtype=int)
def list_set(data):
return list(set(data))
def numpy_unique(data):
return np.unique(data)
def list_dict(data):
return list(dict.fromkeys(data))
b = perfplot.bench(
setup=[
setup_list,
setup_list,
setup_list,
setup_np_array,
setup_np_array,
setup_np_array,
],
kernels=[list_set, numpy_unique, list_dict, list_set, numpy_unique, list_dict],
labels=[
"list(set(lst))",
"np.unique(lst)",
"list(dict(lst))",
"list(set(arr))",
"np.unique(arr)",
"list(dict(arr))",
],
n_range=[2 ** k for k in range(23)],
xlabel="len(array)",
equality_check=None,
)
# plt.title("input array = [0, 1, 2,..., n]")
plt.title("input array = [0, 0,..., 0]")
b.save("out.png")
b.show()
Run Code Online (Sandbox Code Playgroud)
cch*_*lis 12
我的名单中有一个词典,所以我无法使用上述方法.我收到了错误:
TypeError: unhashable type:
Run Code Online (Sandbox Code Playgroud)
因此,如果您关心订单和/或某些商品是不可取消的.然后你可能会觉得这很有用:
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
Run Code Online (Sandbox Code Playgroud)
有些人可能认为列表理解有副作用,不是一个好的解决方案.这是另一种选择:
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
Run Code Online (Sandbox Code Playgroud)
Ped*_*ito 12
很晚的答案。如果您不关心列表顺序,则可以使用*arg具有set唯一性的扩展来删除重复项,即:
l = [*{*l}]
Run Code Online (Sandbox Code Playgroud)
到目前为止,我在这里看到的所有顺序保留方法都使用了初始比较(最好是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]]))]
Run Code Online (Sandbox Code Playgroud)
您可以使用set删除重复项:
mylist = list(set(mylist))
Run Code Online (Sandbox Code Playgroud)
但请注意,结果将是无序的。如果这是一个问题:
mylist.sort()
Run Code Online (Sandbox Code Playgroud)
尝试使用套装:
import sets
t = sets.Set(['a', 'b', 'c', 'd'])
t1 = sets.Set(['a', 'b', 'c'])
print t | t1
print t - t1
Run Code Online (Sandbox Code Playgroud)
这个关心订单而没有太多麻烦(OrderdDict 等)。可能不是最 Pythonic 的方法,也不是最短的方法,但确实有效:
def remove_duplicates(item_list):
''' Removes duplicate items from a list '''
singles_list = []
for element in item_list:
if element not in singles_list:
singles_list.append(element)
return singles_list
Run Code Online (Sandbox Code Playgroud)
你也可以这样做:
>>> 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]
Run Code Online (Sandbox Code Playgroud)
上述原因是该index方法仅返回元素的第一个索引.重复元素具有更高的索引.请参考这里:
list.index(x [,start [,end]])
在值为x的第一个项的列表中返回从零开始的索引.如果没有这样的项,则引发ValueError.
如果您想保留订单,并且不使用任何外部模块,则可以通过以下简便方法进行操作:
>>> 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]
Run Code Online (Sandbox Code Playgroud)
注意:此方法保留了外观顺序,因此,如前所述,因为它是第一次出现,所以后面将有9个。但是,这与您得到的结果相同
from collections import OrderedDict
ulist=list(OrderedDict.fromkeys(l))
Run Code Online (Sandbox Code Playgroud)
但它更短,并且运行更快。
之所以fromkeys可行,是因为每次函数尝试创建一个新键时,如果该值已经存在,它将简单地覆盖它。但是,这根本不会影响字典,因为fromkeys会创建一个字典,其中所有键都具有value None,因此有效地它消除了所有重复项。
通过保留订单来减少变体:
假设我们有清单:
l = [5, 6, 6, 1, 1, 2, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
减少变量(效率低下):
>>> reduce(lambda r, v: v in r and r or r + [v], l, [])
[5, 6, 1, 2, 3, 4]
Run Code Online (Sandbox Code Playgroud)
速度提高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]
Run Code Online (Sandbox Code Playgroud)
说明:
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]
Run Code Online (Sandbox Code Playgroud)
从列表中删除重复项的最佳方法是使用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']
Run Code Online (Sandbox Code Playgroud)
您可以使用以下功能:
def rem_dupes(dup_list):
yooneeks = []
for elem in dup_list:
if elem not in yooneeks:
yooneeks.append(elem)
return yooneeks
Run Code Online (Sandbox Code Playgroud)
范例:
my_list = ['this','is','a','list','with','dupicates','in', 'the', 'list']
Run Code Online (Sandbox Code Playgroud)
用法:
rem_dupes(my_list)
Run Code Online (Sandbox Code Playgroud)
['this','is','a','list','with','dupicates,'in','the']
还有许多其他答案建议使用不同的方法来执行此操作,但是它们都是批处理操作,其中一些会放弃原始订单。根据您的需要,这可能没问题,但是如果您要按每个值的第一个实例的顺序迭代这些值,并且想即时删除重复项,而一次删除所有重复项,则可以使用此生成器:
def uniqify(iterable):
seen = set()
for item in iterable:
if item not in seen:
seen.add(item)
yield item
Run Code Online (Sandbox Code Playgroud)
这将返回一个生成器/迭代器,因此您可以在可以使用迭代器的任何地方使用它。
for unique_item in uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]):
print(unique_item, end=' ')
print()
Run Code Online (Sandbox Code Playgroud)
输出:
1 2 3 4 5 6 7 8
Run Code Online (Sandbox Code Playgroud)
如果您确实想要a list,则可以执行以下操作:
unique_list = list(uniqify([1, 2, 3, 4, 3, 2, 4, 5, 6, 7, 6, 8, 8]))
print(unique_list)
Run Code Online (Sandbox Code Playgroud)
输出:
[1, 2, 3, 4, 5, 6, 7, 8]
Run Code Online (Sandbox Code Playgroud)
使用集:
a = [0,1,2,3,4,3,3,4]
a = list(set(a))
print a
Run Code Online (Sandbox Code Playgroud)
使用独特的:
import numpy as np
a = [0,1,2,3,4,3,3,4]
a = np.unique(a).tolist()
print a
Run Code Online (Sandbox Code Playgroud)
小智 5
不使用set
data=[1, 2, 3, 1, 2, 5, 6, 7, 8]
uni_data=[]
for dat in data:
if dat not in uni_data:
uni_data.append(dat)
print(uni_data)
Run Code Online (Sandbox Code Playgroud)
还有一种更好的方法,
import pandas as pd
myList = [1, 2, 3, 1, 2, 5, 6, 7, 8]
cleanList = pd.Series(myList).drop_duplicates().tolist()
print(cleanList)
#> [1, 2, 3, 5, 6, 7, 8]
Run Code Online (Sandbox Code Playgroud)
并且订单仍然保留.
在Python中,处理这样的复杂情况非常容易,并且只需通过Python的内置类型即可。
让我告诉你该怎么做!
方法一:一般情况
删除列表中重复元素并仍保持排序顺序的方法(1行代码)
line = [1, 2, 3, 1, 2, 5, 6, 7, 8]
new_line = sorted(set(line), key=line.index) # remove duplicated element
print(new_line)
Run Code Online (Sandbox Code Playgroud)
你会得到结果
[1, 2, 3, 5, 6, 7, 8]
Run Code Online (Sandbox Code Playgroud)
方法二:特殊情况
TypeError: unhashable type: 'list'
Run Code Online (Sandbox Code Playgroud)
处理不可散列的特殊情况(3行代码)
line=[['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['16.4966155686595', '-27.59776154691', '52.3786295521147']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['17.6508629295574', '-27.143305738671', '47.534955022564']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['18.8051102904552', '-26.688849930432', '42.6912804930134']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['19.5504702331098', '-26.205884452727', '37.7709192714727']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']
,['20.2929416861422', '-25.722717575124', '32.8500163147157']]
tuple_line = [tuple(pt) for pt in line] # convert list of list into list of tuple
tuple_new_line = sorted(set(tuple_line),key=tuple_line.index) # remove duplicated element
new_line = [list(t) for t in tuple_new_line] # convert list of tuple into list of list
print (new_line)
Run Code Online (Sandbox Code Playgroud)
你会得到结果:
[
['16.4966155686595', '-27.59776154691', '52.3786295521147'],
['17.6508629295574', '-27.143305738671', '47.534955022564'],
['18.8051102904552', '-26.688849930432', '42.6912804930134'],
['19.5504702331098', '-26.205884452727', '37.7709192714727'],
['20.2929416861422', '-25.722717575124', '32.8500163147157']
]
Run Code Online (Sandbox Code Playgroud)
因为元组是可散列的,所以您可以轻松地在列表和元组之间转换数据
| 归档时间: |
|
| 查看次数: |
1372276 次 |
| 最近记录: |