我需要一个函数,它接受一个列表并输出True,如果输入列表中的所有元素使用标准相等运算符计算彼此相等,否则输出False。
我觉得最好是遍历列表,比较相邻的元素,然后与所有结果布尔值。但我不知道最python的方法是什么。
我需要一个函数,它接受一个列表并输出True,如果输入列表中的所有元素使用标准相等运算符计算彼此相等,否则输出False。
我觉得最好是遍历列表,比较相邻的元素,然后与所有结果布尔值。但我不知道最python的方法是什么。
当前回答
出现使用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)
您可以考虑使用许多其他的一行程序:
Converting the input to a set and checking that it only has one or zero (in case the input is empty) items def all_equal2(iterator): return len(set(iterator)) <= 1 Comparing against the input list without the first item def all_equal3(lst): return lst[:-1] == lst[1:] Counting how many times the first item appears in the list def all_equal_ivo(lst): return not lst or lst.count(lst[0]) == len(lst) Comparing against a list of the first element repeated def all_equal_6502(lst): return not lst or [lst[0]]*len(lst) == lst
但它们也有一些缺点,即:
all_equal and all_equal2 can use any iterators, but the others must take a sequence input, typically concrete containers like a list or tuple. all_equal and all_equal3 stop as soon as a difference is found (what is called "short circuit"), whereas all the alternatives require iterating over the entire list, even if you can tell that the answer is False just by looking at the first two elements. In all_equal2 the content must be hashable. A list of lists will raise a TypeError for example. all_equal2 (in the worst case) and all_equal_6502 create a copy of the list, meaning you need to use double the memory.
在Python 3.9中,使用perfplot,我们得到这些计时(越低的Runtime [s]越好):
其他回答
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
适用于Python 2.4,它没有“all”。
这是一种简单的方法:
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)
您可以将列表转换为集合。集合不能有重复项。所以如果原始列表中的所有元素都是相同的,那么集合就只有一个元素。
if len(set(input_list)) == 1:
# input_list has all identical elements.
使用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)
注意,下一个(g, True)总是True(它不是一个非空元组就是True)。这意味着它的值不重要。它的执行纯粹是为了推进groupby迭代器。但是在返回表达式中包含它会导致读者认为它的值在那里被使用。因为它没有,我发现这是误导和不必要的复杂。我上面的第二个版本将next(g, True)视为它的实际用途,作为一个我们不关心其值的语句。
我的第三个版本走了一个不同的方向,并使用了第一个next的值(g, False)。如果根本没有第一个组(即,如果给定的可迭代对象为“空”),则该解决方案立即返回结果,甚至不检查是否有第二个组。
我的第一个解决方案基本上和第三个一样,只是使用任何一个。两种解决方案都读作“所有元素都是相等的……”没有第一组,也没有第二组。”
基准测试结果(虽然速度并不是我在这里的重点,但清晰才是重点,在实践中,如果有许多相等的值,大多数时间可能由组自己花费,减少了这些差异的影响):
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()
或者使用numpy的diff方法:
import numpy as np
def allthesame(l):
return np.unique(l).shape[0]<=1
并呼吁:
print(allthesame([1,1,1]))
输出:
True