[英]Checking if all elements in a list are unique
檢查列表中所有元素是否唯一的最佳方法(最好是傳統方法)是什么?
我目前使用Counter
的方法是:
>>> x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
>>> counter = Counter(x)
>>> for values in counter.itervalues():
if values > 1:
# do something
我可以做得更好嗎?
不是最有效的,但直截了當和簡潔:
if len(x) > len(set(x)):
pass # do something
可能不會對短名單產生太大影響。
這是一個兩班輪,也將提前退出:
>>> 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 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))
是最快的方法。
速度:
import numpy as np
x = [1, 1, 1, 2, 3, 4, 5, 6, 2]
np.unique(x).size == len(x)
如何將所有條目添加到集合並檢查其長度?
len(set(x)) == len(x)
替代set
,您可以使用dict
。
len({}.fromkeys(x)) == len(x)
完全使用 sorted 和 groupby 的另一種方法:
from itertools import groupby
is_unique = lambda seq: all(sum(1 for _ in x[1])==1 for x in groupby(sorted(seq)))
它需要排序,但在第一個重復值上退出。
這是一個有趣的遞歸 O(N 2 ) 版本:
def is_unique(lst):
if len(lst) > 1:
return is_unique(s[1:]) and (s[0] not in s[1:])
return True
這是一個遞歸的提前退出函數:
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)
它對我來說已經足夠快了,而無需使用怪異(緩慢)的轉換,同時具有功能風格的方法。
這個怎么樣
def is_unique(lst):
if not lst:
return True
else:
return Counter(lst).most_common(1)[0][1]==1
上面的所有答案都很好,但我更喜歡使用30 秒 python 中的all_unique
示例
您需要在給定列表上使用set()
來刪除重復項,將其長度與列表的長度進行比較。
def all_unique(lst):
return len(lst) == len(set(lst))
如果平面列表中的所有值都是unique
,則返回True
,否則返回False
。
x = [1, 2, 3, 4, 5, 6]
y = [1, 2, 2, 3, 4, 5]
all_unique(x) # True
all_unique(y) # False
當且僅當您的依賴項中有數據處理庫 pandas 時,有一個已經實現的解決方案可以提供您想要的布爾值:
import pandas as pd
pd.Series(lst).is_unique
在 Pandas 數據框中使用類似的方法來測試列的內容是否包含唯一值:
if tempDF['var1'].size == tempDF['var1'].unique().size:
print("Unique")
else:
print("Not unique")
對我來說,這在包含超過一百萬行的日期幀中的 int 變量上是瞬時的。
您可以使用 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
它並不完全適合這個問題,但是如果你用谷歌搜索我讓你得到的這個問題排名第一的任務,它可能會引起用戶的興趣,因為它是問題的擴展。 如果要調查每個列表元素是否唯一,可以執行以下操作:
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))
非常有效,但不值得為此目的進行排序。
我將建議的解決方案與perfplot進行了比較,發現
len(lst) == len(set(lst))
確實是最快的解決方案。 如果列表中有早期重復項,則首選一些恆定時間解決方案。
重現 plot 的代碼:
import perfplot
import numpy as np
import pandas as pd
def len_set(lst):
return len(lst) == len(set(lst))
def set_add(lst):
seen = set()
return not any(i in seen or seen.add(i) for i in lst)
def list_append(lst):
seen = list()
return not any(i in seen or seen.append(i) for i in lst)
def numpy_unique(lst):
return np.unique(lst).size == len(lst)
def set_add_early_exit(lst):
s = set()
for item in lst:
if item in s:
return False
s.add(item)
return True
def pandas_is_unique(lst):
return pd.Series(lst).is_unique
def sort_diff(lst):
return not np.any(np.diff(np.sort(lst)) == 0)
b = perfplot.bench(
setup=lambda n: list(np.arange(n)),
title="All items unique",
# setup=lambda n: [0] * n,
# title="All items equal",
kernels=[
len_set,
set_add,
list_append,
numpy_unique,
set_add_early_exit,
pandas_is_unique,
sort_diff,
],
n_range=[2**k for k in range(18)],
xlabel="len(lst)",
)
b.save("out.png")
b.show()
對於初學者:
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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.