检查列表中的所有元素是否相同

我需要以下function:

input :一个list

输出

  • 如果input列表中的所有元素使用标准相等运算符评估为相等,则为True ;
  • 否则为False

性能 :当然,我宁愿不招致任何不必要的开销。

我觉得最好是:

  • 遍历列表
  • 比较相邻的元素
  • 和所有的结果布尔值

但我不确定什么是最Python的方式来做到这一点。


编辑

谢谢你所有的好的答案。 我评价了几个,在@KennyTM和@Ivan van der Wijk解决scheme之间select真的很困难。

短路特性的缺乏只会影响早期具有不相等元素的长input(超过50个元素)。 如果这种情况经常发生(多长时间取决于列表可能会多长时间),则需要进行短路。 最好的短路algorithm似乎是@KennyTM checkEqual1 。 但是,这付出了巨大的代价:

  • 性能几乎相同的列表中高达20倍
  • 在短名单上的performance高达2.5倍

如果具有早期不相等元素的长input不会发生(或者很less发生),则不需要短路。 那么,迄今为止最快的是@Ivo van der Wijk解决scheme。

一般方法:

 def checkEqual1(iterator): iterator = iter(iterator) try: first = next(iterator) except StopIteration: return True return all(first == rest for rest in iterator) 

一内胆:

 def checkEqual2(iterator): return len(set(iterator)) <= 1 

另外一行:

 def checkEqual3(lst): return lst[1:] == lst[:-1] 

这三个版本的区别在于:

  1. checkEqual2 ,内容必须是可散列的。
  2. checkEqual1checkEqual2可以使用任何迭代器,但checkEqual3必须采用序列input,通常是像列表或元组这样的具体容器。
  3. 一旦发现差异, checkEqual1停止。
  4. 由于checkEqual1包含更多的Python代码,因此在开始时许多项目相等时效率较低。
  5. 由于checkEqual2checkEqual3总是执行O(N)复制操作,如果大部分input将返回False,则它们将花费更长的时间。
  6. checkEqual2checkEqual3不能轻易改为采用比较a is b而不是a == b

timeit结果,对于Python 2.7和(只有s1,s4,s7,s9应该返回True)

 s1 = [1] * 5000 s2 = [1] * 4999 + [2] s3 = [2] + [1]*4999 s4 = [set([9])] * 5000 s5 = [set([9])] * 4999 + [set([10])] s6 = [set([10])] + [set([9])] * 4999 s7 = [1,1] s8 = [1,2] s9 = [] 

我们得到

  | checkEqual1 | checkEqual2 | checkEqual3 | checkEqualIvo | checkEqual6502 | |-----|-------------|-------------|--------------|---------------|----------------| | s1 | 1.19 msec | 348 usec | 183 usec | 51.6 usec | 121 usec | | s2 | 1.17 msec | 376 usec | 185 usec | 50.9 usec | 118 usec | | s3 | 4.17 usec | 348 usec | 120 usec | 264 usec | 61.3 usec | | | | | | | | | s4 | 1.73 msec | | 182 usec | 50.5 usec | 121 usec | | s5 | 1.71 msec | | 181 usec | 50.6 usec | 125 usec | | s6 | 4.29 usec | | 122 usec | 423 usec | 61.1 usec | | | | | | | | | s7 | 3.1 usec | 1.4 usec | 1.24 usec | 0.932 usec | 1.92 usec | | s8 | 4.07 usec | 1.54 usec | 1.28 usec | 0.997 usec | 1.79 usec | | s9 | 5.91 usec | 1.25 usec | 0.749 usec | 0.407 usec | 0.386 usec | 

注意:

 # http://stackoverflow.com/q/3844948/ def checkEqualIvo(lst): return not lst or lst.count(lst[0]) == len(lst) # http://stackoverflow.com/q/3844931/ def checkEqual6502(lst): return not lst or [lst[0]]*len(lst) == lst 

比使用set()对序列(而不是可迭代)起作用的解决scheme更快的方法是简单地计算第一个元素。 这假定列表是非空的(但这是微不足道的检查,并决定自己的结果应该在一个空的列表)

 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 

最简单最优雅的方式如下:

 all(x==myList[0] for x in myList) 

(是的,这甚至与空列表一起工作!这是因为这是less数python有惰性语义的情况之一)。

关于性能,这将在最早的时间失败,所以它是渐近最佳的。

您可以将列表转换为一个集合。 一套不能有重复。 所以如果原始列表中的所有元素都是相同的,那么这个集合将只有一个元素。

 if len(sets.Set(input_list)) == 1 // input_list has all identical elements. 

一套比较工作:

 len(set(the_list)) == 1 

使用set删除所有重复的元素。

这是另一种select,对于长列表来说比len(set(x))==1更快(使用短路)

 def constantList(x): return x and [x[0]]*len(x) == x 

对于它的价值,最近在python-ideas邮件列表上出现了。 事实certificate,这已经是一个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) 

据说,它performance非常好,并有一些不错的属性。

  1. 短路:一旦发现第一个不相等的项目,就会停止从迭代中消耗项目。
  2. 不要求物品可以被排除。
  3. 这是懒惰的,只需要O(1)额外的内存来做检查。

1换句话说,我不能拿出解决scheme的功劳 – 我也不能因为find解决scheme而信任。

怀疑这是“最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 

会做的伎俩。

这是一个简单的方法:

 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) 

我会做:

 not any((x[i] != x[i+1] for i in range(0, len(x)-1))) 

因为any一旦停止search可迭代,只要它发现一个True条件。

如果你对一些更可读的东西感兴趣(当然,效率不高),你可以尝试:

 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使用reduce() 。 这是一个工作代码,我个人认为比其他答案更好。

 reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2)) 

如果所有项目都相同,则返回第一个值为布尔值的真值。

 def allTheSame(i): j = itertools.groupby(i) for k in j: break for k in j: return False return True 

在Python 2.4中工作,没有“全部”。

将列表转换为集合,然后查找集合中元素的数量。 如果结果是1,则它具有相同的元素,如果不是,则列表中的元素不相同。

 list1 = [1,1,1] len(set(list1)) = 1 list1 = [1,2,3] len(set) 

检查是否所有元素都等于第一个。

np.allclose(array, array[0])

可以使用地图和lambda

 lst = [1,1,1,1,1,1,1,1,1] print all(map(lambda x: x == lst[0], lst[1:])) 
 >>> 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" 

你可以做:

 reduce(and_, (x==yourList[0] for x in yourList), True) 

python让你导入operator.and_这样的operator.and_是相当麻烦的。 从python3开始,你还需要导入functools.reduce

(你不应该使用这个方法,因为如果它发现不相等的值,它不会中断,但是会继续检查整个列表,这里只是作为完整性的一个答案。

 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)))