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

时间:2010-10-02 07:31:11

标签: python algorithm comparison

我需要以下功能:

输入list

输出

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

效果:当然,我不想招致任何不必要的开销。

我认为最好:

  • 遍历列表
  • 比较相邻元素
  • AND所有生成的布尔值

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


修改

谢谢你们所有的好答案。我评价了几个,在@KennyTM和@Ivo van der Wijk解决方案之间选择真的很难。

缺少短路功能只会对早期具有不相等元素的长输入(超过约50个元素)造成伤害。如果这种情况经常发生(通常取决于列表的长度),则需要进行短路。最好的短路算法似乎是@KennyTM checkEqual1。然而,这为此付出了巨大的代价:

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

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

29 个答案:

答案 0 :(得分:351)

一般方法:

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]

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

  1. checkEqual2中,内容必须是可以播放的。
  2. checkEqual1checkEqual2可以使用任何迭代器,但checkEqual3必须接受序列输入,通常是列表或元组之类的具体容器。
  3. 只要找到差异,
  4. checkEqual1就会停止。
  5. 由于checkEqual1包含更多Python代码,因此在开始时许多项目相同时效率较低。
  6. 由于checkEqual2checkEqual3始终执行O(N)复制操作,如果您的大部分输入都返回False,则会花费更长的时间。
  7. 对于checkEqual2checkEqual3,更难以适应从a == ba is b的比较。

  8. 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
    

答案 1 :(得分:261)

比使用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

答案 2 :(得分:124)

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

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

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

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

答案 3 :(得分:36)

一组比较工作:

len(set(the_list)) == 1

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

答案 4 :(得分:24)

您可以将列表转换为一组。一套不能有重复。因此,如果原始列表中的所有元素都相同,则该集合将只有一个元素。

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

答案 5 :(得分:15)

对于它的价值,这最近出现在python-ideas mailing list。事实证明,已经有itertools recipe这样做: 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)

据说它表现得非常好,并且有一些不错的属性。

  1. 短路:一旦找到第一个不相等的项目,就会停止从迭代中消耗物品。
  2. 不要求物品可以清洗。
  3. 这是懒惰的,只需要额外的O(1)内存来进行检查。
  4. 1 换句话说,我无法提出解决方案 - 即使找到也不能归功于我它

答案 6 :(得分:14)

这是两种简单的方法

使用set()

将列表转换为集合时,将删除重复的元素。因此,如果转换后的集合的长度为1,则意味着所有元素都相同。

len(set(input_list))==1

这是一个例子

>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1  # == 3
False
>>> len(set(b))==1  # == 1
True

使用all()

这会将输入列表的第一个元素与列表中的每个其他元素进行比较(等效)。如果相等,则返回True,否则返回False。

all(element==input_list[0] for element in input_list)

这是一个例子

>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True

P.S如果要检查整个列表是否等于某个值,则可以为input_list [0]设置该值。

答案 7 :(得分:10)

这是另一个选项,对于长列表(使用短路)比len(set(x))==1更快

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

答案 8 :(得分:7)

这是一种简单的方法:

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)

答案 9 :(得分:4)

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

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

答案 10 :(得分:4)

怀疑这是“最恐怖的”,但有点像:

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

会做到这一点。

答案 11 :(得分:3)

关于将reduce()lambda一起使用。这是一个我个人认为比其他一些答案更好的工作代码。

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

返回一个truple,如果所有项目相同或不相同,则第一个值为布尔值。

答案 12 :(得分:3)

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

np.allclose(array, array[0])

答案 13 :(得分:3)

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

list1 = [1,1,1]
len(set(list1)) 
>1

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

答案 14 :(得分:3)

我会这样做:

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

any一旦找到True条件,就会停止搜索迭代。

答案 15 :(得分:2)

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

适用于Python 2.4,它没有“全部”。

答案 16 :(得分:2)

可以使用map和lambda

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))

答案 17 :(得分:2)

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

答案 18 :(得分:1)

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

答案 19 :(得分:1)

你可以这样做:

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

令人讨厌的是python让你导入像operator.and_这样的运算符。从python3开始,您还需要导入functools.reduce

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

答案 20 :(得分:1)

将列表更改为一组。然后,如果集合的大小只有1,它们必须是相同的。

if len(set(my_list)) == 1:

答案 21 :(得分:1)

还有一个纯Python递归选项:

 def checkEqual(lst):
    if len(lst)==2 :
        return lst[0]==lst[1]
    else:
        return lst[0]==lst[1] and checkEqual(lst[1:])

但是,由于某些原因,在某些情况下它比其他选项要慢两个数量级。从C语言的心态来看,我期望这会更快,但事实并非如此!

另一个缺点是Python中存在递归限制,在这种情况下需要对其进行调整。例如,使用this

答案 22 :(得分:1)

或使用numpy的diff方法:

import numpy as np
def allthesame(l):
    return np.all(np.diff(l)==0)

并致电:

print(allthesame([1,1,1]))

输出:

True

答案 23 :(得分:1)

或使用numpy的diff方法:

import numpy as np
def allthesame(l):
    return np.unique(l).shape[0]<=1

并致电:

print(allthesame([1,1,1]))

输出:

答案 24 :(得分:1)

简单的解决方案是在列表上应用设置

如果所有元素都相同,则len将大于1,否则将大于1

# script.awk is the one mentioned in James Brown's answer
# result here shown with GNU awk
$ time LC_ALL=C awk -f script.awk small.bam > f1
real    0m0.092s

# mawk is faster compared to GNU awk for this use case
$ time LC_ALL=C mawk -f script.awk small.bam > f2
real    0m0.054s

$ time perl -ne '$h{$&}++ if /CB:Z:\K[ACGT]++/; END{print "$_ $h{$_}\n" for keys %h}' small.bam > f3
real    0m0.064s

$ diff -sq <(sort f1) <(sort f2)
Files /dev/fd/63 and /dev/fd/62 are identical
$ diff -sq <(sort f1) <(sort f3)
Files /dev/fd/63 and /dev/fd/62 are identical

答案 25 :(得分:0)

您可以使用.nunique()查找列表中唯一数量的项目。

def identical_elements(list):
    series = pd.Series(list)
    if series.nunique() == 1: identical = True
    else:  identical = False
    return identical



identical_elements(['a', 'a'])
Out[427]: True

identical_elements(['a', 'b'])
Out[428]: False

答案 26 :(得分:0)

您可以使用set。它将设置并删除重复的元素。然后检查其元素是否超过1个。

if len(set(your_list)) <= 1:
    print('all ements are equal')

示例:

>>> len(set([5, 5])) <= 1
True

答案 27 :(得分:0)

也许我低估了这个问题?检查列表中唯一值的长度。

lzt = [1,1,1,1,1,2]

if (len(set(lzt)) > 1):
    uniform = False
elif (len(set(lzt)) == 1):
    uniform = True
elif (not lzt):
    raise ValueError("List empty, get wrecked")

答案 28 :(得分:0)

我认为这是一个具有大量 Pythonicity 以及简单性和显而易见性的平衡的代码,它应该也适用于非常旧的 Python 版本。

def all_eq(lst):
    for idx, itm in enumerate(lst):
        if not idx:   # == 0
            prev = itm
        if itm != prev:
            return False
        prev = itm
    return True
相关问题