提问人:max 提问时间:10/2/2010 最后编辑:max 更新时间:9/12/2023 访问量:607782
检查列表中的所有元素是否相同
Check if all elements in a list are identical
问:
我需要一个函数,如果输入列表中的所有元素都使用标准相等运算符计算结果,则该函数将接受 a 并输出。list
True
False
我觉得最好遍历列表,比较相邻元素,然后遍历所有生成的布尔值。但我不确定最 Python 的方法是什么。AND
答:
怀疑这是“最 Pythonic”,但就像:
>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>>
>>> def testList(list):
... for item in list[1:]:
... if item != list[0]:
... return False
... return True
...
>>> testList(falseList)
False
>>> testList(trueList)
True
会做这个伎俩。
评论
for
if any(item != list[0] for item in list[1:]): return False
使用 itertools.groupby
(参见 itertools
配方):
from itertools import groupby
def all_equal(iterable):
g = groupby(iterable)
return next(g, True) and not next(g, False)
或不:groupby
def all_equal(iterator):
iterator = iter(iterator)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == x for x in iterator)
您可以考虑使用许多替代的单行代码:
将输入转换为集合并检查它是否只有一个或零个(如果输入为空)项
def all_equal2(iterator): return len(set(iterator)) <= 1
与没有第一项的输入列表进行比较
def all_equal3(lst): return lst[:-1] == lst[1:]
-
def all_equal_ivo(lst): return not lst or lst.count(lst[0]) == len(lst)
-
def all_equal_6502(lst): return not lst or [lst[0]]*len(lst) == lst
但它们有一些缺点,即:
all_equal
并且可以使用任何迭代器,但其他迭代器必须接受序列输入,通常是具体容器,如列表或元组。all_equal2
all_equal
一旦发现差异就停止(所谓的“短路”),而所有替代方案都需要遍历整个列表,即使您可以通过查看前两个元素来判断答案。all_equal3
False
- 在内容中必须是可散列的。例如,列表列表将引发一个。
all_equal2
TypeError
all_equal2
(在最坏的情况下)并创建列表的副本,这意味着您需要使用双倍的内存。all_equal_6502
在 Python 3.9 上,使用 perfplot
,我们得到这些时间(越低越好):Runtime [s]
评论
obj.__eq__
lhs is rhs
first == second and second == third and ...
pytest
您可以将列表转换为集合。一个集合不能有重复项。因此,如果原始列表中的所有元素都相同,则该集合将只有一个元素。
if len(set(input_list)) == 1:
# input_list has all identical elements.
评论
False
True
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"
这是一种简单的方法:
result = mylist and all(mylist[0] == elem for elem in mylist)
这稍微复杂一些,它会产生函数调用开销,但语义更清楚地说明出来:
def all_identical(seq):
if not seq:
# empty list is False.
return False
first = seq[0]
return all(first == elem for elem in seq)
评论
for elem in mylist[1:]
elem[0] is elem[0]
这是另一种选择,比长列表(使用短路)更快len(set(x))==1
def constantList(x):
return x and [x[0]]*len(x) == x
评论
比使用 set() 处理序列(而不是可迭代对象)更快的解决方案是简单地计算第一个元素。这假设列表是非空的(但这很容易检查,并自己决定空列表上的结果应该是什么)
x.count(x[0]) == len(x)
一些简单的基准测试:
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777
评论
x.count(next(x)) == len(x)
count
len
.count()
count
list
count
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
适用于 Python 2.4,它没有“全部”。
评论
for k in j: break
等效于 。如果你不关心效率,你也可以这样做。next(j)
def allTheSame(x): return len(list(itertools.groupby(x))<2)
我会做:
not any((x[i] != x[i+1] for i in range(0, len(x)-1)))
一旦找到条件,就会停止搜索可迭代对象。any
True
评论
all()
all(x == seq[0] for x in seq)
[编辑:这个答案解决了目前投票最多的(这是一个很好的答案)答案。itertools.groupby
在不重写程序的情况下,最渐近性能和最易读性的方式如下:
all(x==myList[0] for x in myList)
(是的,这甚至适用于空列表!这是因为这是 python 具有惰性语义的少数情况之一。
这将在尽可能早的时间失败,因此它是渐近最优的(预期时间大约是 O(#uniques) 而不是 O(N),但最坏情况下的时间仍然是 O(N))。这是假设您以前没有看过数据......
(如果你关心性能,但不太关心性能,你可以先做通常的标准优化,比如将常量从循环中提升出来,并为边缘情况添加笨拙的逻辑,尽管这是 python 编译器最终可能会学会如何做的事情,因此除非绝对必要,否则不应该这样做, 因为它会破坏可读性以获得最小的收益。myList[0]
如果您稍微关心性能,这比上面快两倍,但更冗长一些:
def allEqual(iterable):
iterator = iter(iterable)
try:
firstItem = next(iterator)
except StopIteration:
return True
for x in iterator:
if x!=firstItem:
return False
return True
如果您更关心性能(但不足以重写您的程序),请使用当前投票最多的答案,它的速度是因为它可能是优化的 C 代码的两倍。(根据文档,它应该(类似于这个答案)没有任何内存开销,因为惰性生成器永远不会被评估到列表中......有人可能会担心,但伪代码显示分组的“列表”实际上是惰性生成器。itertools.groupby
allEqual
如果您更关心性能,请继续阅读......
关于性能的旁注,因为其他答案出于某种未知原因谈论它:
...如果您以前看过这些数据,并且可能正在使用某种集合数据结构,并且您真的很关心性能,那么您可以通过使用计数器来增强您的结构,该
计数器
会随着每个插入/删除/等操作而更新,并且只需检查它是否是 {something:someCount}
即 len(counter.keys())==1
;或者,您可以将计数器放在单独的变量中。事实证明,这比其他任何常数都要好。也许您也可以将 python 的 FFI 与您选择的方法一起使用,也可以使用启发式方法(例如,如果它是带有 getitem 的序列,然后检查第一个元素、最后一个元素,然后按顺序检查元素)。ctypes
当然,对于可读性,有一些话要说。
评论
checkEqual1
first=myList[0]
all(x==first for x in myList)
first=myList[0]
IndexError
x==myList[0]
all
您可以执行以下操作:
reduce(and_, (x==yourList[0] for x in yourList), True)
python 让你导入像 .从 python3 开始,您还需要导入 .operator.and_
functools.reduce
(不应使用此方法,因为如果找到不相等的值,它不会中断,但会继续检查整个列表。它只是作为完整性的答案包含在内。
如果你对一些可读性更强的东西感兴趣(但当然没有那么高效),你可以尝试:
def compare_lists(list1, list2):
if len(list1) != len(list2): # Weed out unequal length lists.
return False
for item in list1:
if item not in list2:
return False
return True
a_list_1 = ['apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'apple']
b_list_1 = ['apple', 'orange', 'grape', 'pear']
b_list_2 = ['apple', 'orange', 'banana', 'pear']
c_list_1 = ['apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']
print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False
评论
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]
下一个会短路:
all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
评论
reduce(lambda a,b:a==b, [2,2,2])
False
将您的输入转换为一组
:
len(set(the_list)) <= 1
using 将删除所有重复的元素。 以便它在输入为空时正确返回。set
<= 1
True
这要求输入中的所有元素都是可散列的。例如,如果你传入一个列表列表,你会得到一个。TypeError
关于与 .这是一个工作代码,我个人认为它比其他一些答案要好得多。reduce()
lambda
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
返回一个元组,如果所有项都相同或不相同,则第一个值是布尔值。
评论
[1, 2, 2]
x[1] == y
x[0] and x[1] == y
值得一提的是,这最近出现在 python-ideas 邮件列表上。事实证明,已经有一个 itertools 配方可以做到这一点:1
def all_equal(iterable):
"Returns True if all the elements are equal to each other"
g = groupby(iterable)
return next(g, True) and not next(g, False)
据说它的表现非常好,并且有一些不错的特性。
- 短路:一旦找到第一个不相等的项,它就会停止消耗可迭代对象中的项。
- 不要求项目是可散列的。
- 它是懒惰的,只需要 O(1) 个额外的内存来执行检查。
1換句話說,我不能把提出解決方案的功譽歸負責,也不能負責找到解決方案。
评论
return next(g, f := next(g, g)) == f
(当然来自 py3.8)
检查所有元素是否都等于第一个元素。
np.allclose(array, array[0])
评论
可以使用 map 和 lambda
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
评论
==
1:
all(map(lambda x: x == lst[0], lst))
还有一个纯 Python 递归选项:
def checkEqual(lst):
if len(lst)==2 :
return lst[0]==lst[1]
else:
return lst[0]==lst[1] and checkEqual(lst[1:])
但是,由于某种原因,在某些情况下,它比其他选项慢两个数量级。从C语言的心态来看,我本以为这会更快,但事实并非如此!
另一个缺点是 Python 中有递归限制,在这种情况下需要调整。例如,使用这个。
或者使用numpy的方法:diff
import numpy as np
def allthesame(l):
return np.all(np.diff(l)==0)
并致电:
print(allthesame([1,1,1]))
输出:
True
评论
not np.any(np.diff(l))
或者使用 numpy 的 diff 方法:
import numpy as np
def allthesame(l):
return np.unique(l).shape[0]<=1
并致电:
print(allthesame([1,1,1]))
输出:
真
评论
您可以使用它来查找列表中唯一项的数量。.nunique()
def identical_elements(list):
series = pd.Series(list)
if series.nunique() == 1: identical = True
else: identical = False
return identical
identical_elements(['a', 'a'])
Out[427]: True
identical_elements(['a', 'b'])
Out[428]: False
评论
简单的解决方案是应用列表上的集合
如果所有元素都相同,则 len 将为 1 或大于 1
lst = [1,1,1,1,1,1,1,1,1]
len_lst = len(list(set(lst)))
print(len_lst)
1
lst = [1,2,1,1,1,1,1,1,1]
len_lst = len(list(set(lst)))
print(len_lst)
2
评论
也许我低估了这个问题?检查列表中唯一值的长度。
lzt = [1,1,1,1,1,2]
if (len(set(lzt)) > 1):
uniform = False
elif (len(set(lzt)) == 1):
uniform = True
elif (not lzt):
raise ValueError("List empty, get wrecked")
评论
我认为,这是一个具有大量 Pythonicity 的代码,并且在简单性和明显性之间取得了平衡,它也应该适用于非常旧的 Python 版本。
def all_eq(lst):
for idx, itm in enumerate(lst):
if not idx: # == 0
prev = itm
if itm != prev:
return False
prev = itm
return True
评论
all_eq([])
这是一个有趣的阅读和思考。谢谢大家! 我不认为任何依赖纯计数的东西在所有情况下都是可靠的。此外,sum 也可以工作,但仅适用于数字或长度(再次导致计数场景)。
但我确实喜欢它的简单性,所以这就是我想出的:
all(i==lst[c-1] for c, i in enumerate(lst))
或者,我确实认为这种聪明的 @kennytm 也适用于所有情况(有趣的是,这可能是最快的)。所以我承认它可能比我的更好:
[lst[0]]*len(lst) == lst
我认为一个聪明的小奖励也会起作用,因为 set 可以消除重复项(聪明很有趣,但通常不是维护代码的最佳实践)。而且我认为一个@kennytm仍然会更快,但实际上只与大型列表相关:
len(set(lst)) == 1
但 Python 的简单性和聪明性是我最喜欢的语言之一。再想一想,如果你无论如何都必须修改列表,就像我实际上所做的那样,因为我正在比较地址(并且会删除前导/尾随空格并转换为小写以消除可能的不一致,我的会更适合这项工作)。所以“更好”是主观的,因为我在使用这个词时使用引号来回避!但您也可以事先清理列表。
祝你好运!
评论
-1
.例如,这些审议并没有增加太多,例如,@ninjagecko早在2012年的回答: .这里提出的顶级解决方案与此类似,但性能较差且更难理解。all(x==myList[0] for x in myList)
最佳答案
有一个很好的 Twitter 帖子,介绍了实现 all_equal() 函数的各种方法。
给定列表输入,最佳提交是:
t.count(t[0]) == len(t)
其他方法
以下是该线程的结果:
让 groupby() 比较相邻的条目。这有一个不匹配的早期退出,不使用额外的内存,并且它以 C 速度运行。
g = itertools.groupby(s) next(g, True) and not next(g, False)
比较两个切片彼此偏移一个位置。这会占用额外的内存,但以 C 速度运行。
s[1:] == s[:-1]
切片比较的迭代器版本。它以 C 速度运行,不使用额外的内存;但是,EQ调用很昂贵。
all(map(operator.eq, s, itertools.islice(s, 1, None)))
比较最低值和最高值。它以 C 速度运行,不使用额外的内存,但每个基准需要两次不等式检验。
min(s) == max(s) # s must be non-empty
构建一个集合。它以 C 速度运行,几乎不使用额外的内存,但需要哈希性并且没有提前退出。
len(set(t))==1.
这花费了巨大的成本,可以处理 NaN 和其他具有奇异相等关系的对象。
all(itertools.starmap(eq, itertools.product(s, repeat=2)))
拉出第一个元素并将其所有其他元素与它进行比较,在第一个不匹配处停止。唯一的缺点是它不能以 C 速度运行。
it = iter(s) a = next(it, None) return all(a == b for b in it)
只需数第一个元素。这是快速、简单、优雅的。它以 C 速度运行,不需要额外的内存,仅使用相等性测试,并且仅对数据进行一次传递。
t.count(t[0]) == len(t)
评论
product
min(map(s.count, s)) == len(s)
我最终得到了这个单行字
from itertools import starmap, pairwise
all(starmap(eq, (pairwise(x)))
我发现使用的更多版本比原始版本更清晰(更多内容见下文):itertools.groupby
def all_equal(iterable):
g = groupby(iterable)
return not any(g) or not any(g)
def all_equal(iterable):
g = groupby(iterable)
next(g, None)
return not next(g, False)
def all_equal(iterable):
g = groupby(iterable)
return not next(g, False) or not next(g, False)
这是 Itertools Recipes 的原文:
def all_equal(iterable):
g = groupby(iterable)
return next(g, True) and not next(g, False)
请注意,the 始终为 true(它要么是非空的,要么是 )。这意味着它的价值并不重要。它纯粹是为了推进迭代器而执行的。但是在表达式中包含它会导致读者认为它的价值在那里被使用。既然没有,我觉得这具有误导性和不必要的复杂性。我上面的第二个版本将它视为它的实际用途,作为我们不关心其价值的陈述。next(g, True)
tuple
True
groupby
return
next(g, True)
我的第三个版本走了不同的方向,并且确实使用了第一个版本的值。如果根本没有第一个组(即,如果给定的可迭代对象是“空的”),那么该解决方案会立即返回结果,甚至不会检查是否有第二个组。next(g, False)
我的第一个解决方案与我的第三个解决方案基本相同,只是使用 .两种解决方案都读作“所有元素都是平等的......没有第一组,也没有第二组。any
基准测试结果(虽然速度真的不是我在这里的重点,但清晰度是,在实践中,如果有许多相等的值,大部分时间可能会花在本身上,从而减少这些差异的影响):groupby
Python 3.10.4 on my Windows laptop:
iterable = ()
914 ns 914 ns 916 ns use_first_any
917 ns 925 ns 925 ns use_first_next
1074 ns 1075 ns 1075 ns next_as_statement
1081 ns 1083 ns 1084 ns original
iterable = (1,)
1290 ns 1290 ns 1291 ns next_as_statement
1303 ns 1307 ns 1307 ns use_first_next
1306 ns 1307 ns 1309 ns use_first_any
1318 ns 1319 ns 1320 ns original
iterable = (1, 2)
1463 ns 1464 ns 1467 ns use_first_any
1463 ns 1463 ns 1467 ns next_as_statement
1477 ns 1479 ns 1481 ns use_first_next
1487 ns 1489 ns 1492 ns original
Python 3.10.4 on a Debian Google Compute Engine instance:
iterable = ()
234 ns 234 ns 234 ns use_first_any
234 ns 235 ns 235 ns use_first_next
264 ns 264 ns 264 ns next_as_statement
265 ns 265 ns 265 ns original
iterable = (1,)
308 ns 308 ns 308 ns next_as_statement
315 ns 315 ns 315 ns original
316 ns 316 ns 317 ns use_first_any
317 ns 317 ns 317 ns use_first_next
iterable = (1, 2)
361 ns 361 ns 361 ns next_as_statement
367 ns 367 ns 367 ns original
384 ns 385 ns 385 ns use_first_next
386 ns 387 ns 387 ns use_first_any
基准代码:
from timeit import timeit
from random import shuffle
from bisect import insort
from itertools import groupby
def original(iterable):
g = groupby(iterable)
return next(g, True) and not next(g, False)
def use_first_any(iterable):
g = groupby(iterable)
return not any(g) or not any(g)
def next_as_statement(iterable):
g = groupby(iterable)
next(g, None)
return not next(g, False)
def use_first_next(iterable):
g = groupby(iterable)
return not next(g, False) or not next(g, False)
funcs = [original, use_first_any, next_as_statement, use_first_next]
for iterable in (), (1,), (1, 2):
print(f'{iterable = }')
times = {func: [] for func in funcs}
for _ in range(1000):
shuffle(funcs)
for func in funcs:
number = 1000
t = timeit(lambda: func(iterable), number=number) / number
insort(times[func], t)
for func in sorted(funcs, key=times.get):
print(*('%4d ns ' % round(t * 1e9) for t in times[func][:3]), func.__name__)
print()
评论
我建议一个简单的pythonic解决方案:
def all_equal_in_iterable(iterable: Iterable):
iterable = list(iterable)
if not iterable:
return True
return all(item == iterable[0] for item in iterable)
评论
a == b
a is b
functools.reduce(operator.eq, a)
functools.reduce(operator.eq, a)
[True, False, False]
((True == False) == False)
True