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

我需要以下功能:

输入:list

输出:

  • 如果输入列表中的所有元素使用标准相等运算符计算为相等,则为True
  • 其他False

我觉得最好是这样:

  • 循环浏览列表
  • 比较相邻元素
  • AND所有得到的布尔值

但我不确定什么是最Pythonic的方法。


时间:

常规方法:


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

单行:


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

还有一个:


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

3个版本之间的区别在于:

  1. checkEqual2中,内容必须是hashable ,
  2. checkEqual1checkEqual2可以使用迭代器,但是checkEqual3必须采用序列输入,通常是像列表或元组这样的具体容器,
  3. 一旦发现差异,checkEqual1就停止,
  4. 由于checkEqual1包含更多python代码,所以许多项相等时,它的效率就会降低,
  5. 由于checkEqual2和checkEqual3总是执行O(n)复制操作,如果大多数输入都将return false,它们会花更长时间,
  6. checkEqual2checkEqual3不能容易地改变为比较a is b而不是a == b

timeit结果,用于Python 2.7,(仅s1,s4,s7,s9 ),


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


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)

关于性能,这将在可能的时间内失败,因此它是渐近最优的。

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


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


>>> 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发现True条件时,它就停止搜索iterable 。

...