我需要一个函数,它接受一个列表并输出True,如果输入列表中的所有元素使用标准相等运算符计算彼此相等,否则输出False。
我觉得最好是遍历列表,比较相邻的元素,然后与所有结果布尔值。但我不知道最python的方法是什么。
我需要一个函数,它接受一个列表并输出True,如果输入列表中的所有元素使用标准相等运算符计算彼此相等,否则输出False。
我觉得最好是遍历列表,比较相邻的元素,然后与所有结果布尔值。但我不知道最python的方法是什么。
当前回答
[编辑:这个答案针对当前投票最多的itertools。Groupby(这是一个很好的答案)稍后回答。
在不重写程序的情况下,最具渐近性能和可读性的方法如下:
all(x==myList[0] for x in myList)
(是的,这甚至适用于空列表!这是因为这是python具有惰性语义的少数情况之一。)
这将在尽可能早的时间失败,因此它是渐近最优的(期望时间大约是O(#惟一)而不是O(N),但最坏情况时间仍然是O(N))。这是假设你之前没有看过这些数据……
(如果你关心性能,但不太关心性能,你可以先做通常的标准优化,比如将myList[0]常量从循环中提升出来,并为边缘情况添加笨拙的逻辑,尽管这是python编译器最终可能会学会如何做的事情,因此除非绝对必要,否则不应该这样做,因为它会破坏最小收益的可读性。)
如果你更关心性能,这是上面速度的两倍,但有点啰嗦:
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
如果你更关心性能(但还不足以重写你的程序),请使用当前投票最多的itertools。它的速度是allEqual的两倍,因为它可能是优化的C代码。(根据文档,它应该(类似于这个答案)没有任何内存开销,因为惰性生成器永远不会被计算到列表中…这可能会让人担心,但伪代码表明,分组的“列表”实际上是惰性生成器。)
如果你更关心性能,请继续阅读…
关于性能的旁注,因为其他答案都在谈论它,因为一些未知的原因:
... if you have seen the data before and are likely using a collection data structure of some sort, and you really care about performance, you can get .isAllEqual() for free O(1) by augmenting your structure with a Counter that is updated with every insert/delete/etc. operation and just checking if it's of the form {something:someCount} i.e. len(counter.keys())==1; alternatively you can keep a Counter on the side in a separate variable. This is provably better than anything else up to constant factor. Perhaps you can also use python's FFI with ctypes with your chosen method, and perhaps with a heuristic (like if it's a sequence with getitem, then checking first element, last element, then elements in-order).
当然,可读性也有好处。
其他回答
这是一个有趣的阅读和思考。谢谢大家! 我不认为任何依赖于纯计数的方法对所有情况都是可靠的。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的简单和聪明是我最喜欢的语言之一。再想一下,如果你必须修改列表,就像我实际上做的那样,因为我正在比较地址(并将删除开头/结尾空格并转换为小写以消除可能的不一致,我的将更适合这项工作)。所以“更好”是主观的,因为我在使用这个词时使用了引号!但是你也可以事先清理列表。
祝你好运!
您可以将列表转换为集合。集合不能有重复项。所以如果原始列表中的所有元素都是相同的,那么集合就只有一个元素。
if len(set(input_list)) == 1:
# input_list has all identical elements.
我最后写了这样一句话
from itertools import starmap, pairwise
all(starmap(eq, (pairwise(x)))
如果你对一些更有可读性的东西感兴趣(但当然不是那么高效),你可以尝试:
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
出现使用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]越好):