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

2024-03-29 10:29:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要以下功能:

输入:alist

输出

  • True如果输入列表中的所有元素使用标准的相等运算符求值为彼此相等
  • False否则。

性能:当然,我不希望产生任何不必要的开销。

我觉得最好:

  • 遍历列表
  • 比较相邻元素
  • 以及所有的布尔值

但我不知道什么是最Python式的方法。


编辑

谢谢你的回答。我评价了几个,很难在@KennyTM和@Ivo van der Wijk解决方案之间做出选择。

短路特性的缺乏只会损害早期具有不等元件的长输入(超过50个元件)。如果这种情况经常发生(发生的频率取决于列表的长度),则需要短路。最好的短路算法似乎是@KennyTMcheckEqual1。然而,它为此付出了巨大的代价:

  • 性能高达20倍几乎相同的列表
  • 短名单上的绩效高达2.5倍

如果具有早期不等元件的长输入不发生(或很少发生),则不需要短路。到目前为止,最快的是@Ivo van der Wijk解决方案。


Tags: 功能true元素列表标准运算符解决方案性能
3条回答

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

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

(是的,这甚至适用于空列表!这是因为这是python具有惰性语义的少数情况之一。)

在性能方面,这将在尽可能早的时间失败,因此它是渐近最优的。

一个比在序列(不是iterable)上使用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

一般方法:

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必须接受序列输入,通常是列表或元组之类的具体容器。
  3. checkEqual1发现差异后立即停止。
  4. 由于checkEqual1包含更多的Python代码,因此当许多项在开始时相等时,效率会降低。
  5. 由于checkEqual2checkEqual3总是执行O(N)复制操作,因此如果大多数输入返回False,它们将花费更长的时间。
  6. 对于checkEqual2checkEqual3来说,很难适应从a == ba is 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

相关问题 更多 >