检查列表中的所有元素是否唯一

检查列表中所有元素是否唯一的最佳方法是什么?

我目前使用 Counter的方法是:

>>> x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
>>> counter = Counter(x)
>>> for values in counter.itervalues():
if values > 1:
# do something

我能做得更好吗?

131003 次浏览

不是最有效率的,但是直截了当,简洁明了:

if len(x) > len(set(x)):
pass # do something

对于短名单来说可能不会有太大区别。

如何将所有条目添加到一个集合并检查其长度?

len(set(x)) == len(x)

除了 set之外,还可以使用 dict

len({}.fromkeys(x)) == len(x)

提前退出的解决方案可能是

def unique_values(g):
s = set()
for x in g:
if x in s: return False
s.add(x)
return True

然而,对于小的情况下,或者如果早退出不是常见的情况,那么我希望 len(x) != len(set(x))是最快的方法。

您可以使用 Yan 的语法(len (x) > len (set (x))) ,但是不要使用 set (x) ,而是定义一个函数:

 def f5(seq, idfun=None):
# order preserving
if idfun is None:
def idfun(x): return x
seen = {}
result = []
for item in seq:
marker = idfun(item)
# in old Python versions:
# if seen.has_key(marker)
# but in new ones:
if marker in seen: continue
seen[marker] = 1
result.append(item)
return result

然后执行 len (x) > len (f5(x)) ,这样会更快,也能保持顺序。

这里的代码取自: http://www.peterbe.com/plog/uniqifiers-benchmark

这里有一个也可以提前退出的双重暗示:

>>> def allUnique(x):
...     seen = set()
...     return not any(i in seen or seen.add(i) for i in x)
...
>>> allUnique("ABCDEF")
True
>>> allUnique("ABACDEF")
False

如果 x 的元素不是散列的,那么你将不得不使用 seen的列表:

>>> def allUnique(x):
...     seen = list()
...     return not any(i in seen or seen.append(i) for i in x)
...
>>> allUnique([list("ABC"), list("DEF")])
True
>>> allUnique([list("ABC"), list("DEF"), list("ABC")])
False

这个怎么样

def is_unique(lst):
if not lst:
return True
else:
return Counter(lst).most_common(1)[0][1]==1

速度:

import numpy as np
x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
np.unique(x).size == len(x)

另一种完全使用排序和 groupby 的方法:

from itertools import groupby
is_unique = lambda seq: all(sum(1 for _ in x[1])==1 for x in groupby(sorted(seq)))

它需要排序,但在第一个重复值时退出。

下面是一个递归的提前退出函数:

def distinct(L):
if len(L) == 2:
return L[0] != L[1]
H = L[0]
T = L[1:]
if (H in T):
return False
else:
return distinct(T)

对我来说,不使用奇怪(缓慢)的转换就足够快了 具有功能风格的方法。

下面是一个递归 O (N2)版本,以供参考:

def is_unique(lst):
if len(lst) > 1:
return is_unique(s[1:]) and (s[0] not in s[1:])
return True

对于初学者:

def AllDifferent(s):
for i in range(len(s)):
for i2 in range(len(s)):
if i != i2:
if s[i] == s[i2]:
return False
return True

在熊猫数据框架中使用类似的方法来测试一个列的内容是否包含唯一值:

if tempDF['var1'].size == tempDF['var1'].unique().size:
print("Unique")
else:
print("Not unique")

对我来说,在包含超过100万行的数据框架中,对于 int 变量来说,这是瞬时的。

以上的答案都很好,但我更喜欢使用 < strong > 30秒的蟒蛇 中的 all_unique例子

您需要在给定的列表中使用 set()来删除重复项,并将其长度与列表的长度进行比较。

def all_unique(lst):
return len(lst) == len(set(lst))

如果平面列表中的所有值都是 unique,则返回 True

x = [1, 2, 3, 4, 5, 6]
y = [1, 2, 2, 3, 4, 5]
all_unique(x)  # True
all_unique(y)  # False

它并不完全符合这个问题,但如果你谷歌的任务,我有你得到这个问题排名第一,它可能是感兴趣的用户,因为它是一个扩展的问题。如果您希望调查每个列表元素是否唯一,可以执行以下操作:

import timeit
import numpy as np


def get_unique(mylist):
# sort the list and keep the index
sort = sorted((e,i) for i,e in enumerate(mylist))
# check for each element if it is similar to the previous or next one
isunique = [[sort[0][1],sort[0][0]!=sort[1][0]]] + \
[[s[1], (s[0]!=sort[i-1][0])and(s[0]!=sort[i+1][0])]
for [i,s] in enumerate (sort) if (i>0) and (i<len(sort)-1) ] +\
[[sort[-1][1],sort[-1][0]!=sort[-2][0]]]
# sort indices and booleans and return only the boolean
return [a[1] for a in sorted(isunique)]




def get_unique_using_count(mylist):
return [mylist.count(item)==1 for item in mylist]


mylist = list(np.random.randint(0,10,10))
%timeit for x in range(10): get_unique(mylist)
%timeit for x in range(10): get_unique_using_count(mylist)


mylist = list(np.random.randint(0,1000,1000))
%timeit for x in range(10): get_unique(mylist)
%timeit for x in range(10): get_unique_using_count(mylist)

对于短名单的 get_unique_using_count建议在一些答案是快速。但是,如果您的列表已经超过100个元素,count 函数将花费相当长的时间。因此,在 get_unique函数中显示的方法要快得多,尽管它看起来更复杂。

如果列表已经排序,您可以使用:

not any(sorted_list[i] == sorted_list[i + 1] for i in range(len(sorted_list) - 1))

非常高效,但是不值得为此目的进行排序。

如果而且只有当你的依赖项中有数据处理库熊猫时,有一个已经实现的解决方案可以给出你想要的布尔值:

import pandas as pd
pd.Series(lst).is_unique