代码之家  ›  专栏  ›  技术社区  ›  max

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

  •  315
  • max  · 技术社区  · 14 年前

    我需要以下功能:

    输入 :一个 list

    :

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

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

    • 遍历列表
    • AND 所有生成的布尔值

    但我不确定什么是最适合蟒蛇的方式。


    checkEqual1 . 然而,它为此付出了巨大的代价:

    • 性能高达20倍几乎完全相同的列表

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

    24 回复  |  直到 4 年前
        1
  •  425
  •   ankostis    6 年前

    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. checkEqual1 检查等式2 可以使用任何迭代器,但是 checkEqual3 必须接受序列输入,通常是像列表或元组这样的具体容器。
    3. 一旦发现差异就停止。
    4. 检查等式1 包含更多的Python代码,当许多项在一开始是相等的时,效率会降低。
    5. 因为 检查等式2 检查等式3
    6. 检查等式3 a == b a is b .

    timeit 结果,对于python2.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
    
        2
  •  305
  •   Ivo van der Wijk    14 年前

    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
    
        3
  •  169
  •   ninjagecko    5 年前

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

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

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

        4
  •  48
  •   Asclepius    7 年前

    一套比较法:

    len(set(the_list)) == 1
    

    使用 set

        5
  •  26
  •   codaddict    14 年前

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

    if len(sets.Set(input_list)) == 1
    // input_list has all identical elements.
    
        6
  •  21
  •   mgilson    8 年前

    不管怎么说,这件事发生在 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. 短路:一旦找到第一个不相等的项,它将停止消耗iterable中的项。
    2. 它是懒惰的,只需要O(1)个额外的内存来进行检查。

    换言之,我不能因为提出了解决方案而得到赞扬——我甚至也不能认为这是功劳 发现 它。

        7
  •  17
  •   Christopher Nuccio    6 年前

    这里有两种简单的方法

    使用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如果您正在检查整个列表是否等于某个值,则可以在for input_list[0]中替换该值。

        8
  •  12
  •   6502    14 年前

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

    def constantList(x):
        return x and [x[0]]*len(x) == x
    
        9
  •  9
  •   Jerub    14 年前

    这是一种简单的方法:

    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)
    
        10
  •  5
  •   Gusev Slava    8 年前

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

    np.allclose(array, array[0])

        11
  •  4
  •   machineghost    14 年前

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

    会成功的。

        12
  •  4
  •   Joshua Burns    12 年前

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

    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
    
        13
  •  4
  •   Kanmani    6 年前

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

    list1 = [1,1,1]
    len(set(list1)) 
    >1
    
    list1 = [1,2,3]
    len(set(list1)
    >3
    
        14
  •  4
  •   shaik moeed    5 年前

    关于使用 reduce() 具有 lambda . 这里有一个我个人认为比其他答案更好的工作代码。

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

        15
  •  3
  •   Robert Rossney    13 年前

    我会这样做:

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

    any True 条件。

        16
  •  2
  •   pyfunc    14 年前
    >>> 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"
    
        17
  •  2
  •   itertool    13 年前
    def allTheSame(i):
        j = itertools.groupby(i)
        for k in j: break
        for k in j: return False
        return True
    

        18
  •  2
  •   SuperNova    7 年前

    可以使用map和lambda

    lst = [1,1,1,1,1,1,1,1,1]
    
    print all(map(lambda x: x == lst[0], lst[1:]))
    
        19
  •  2
  •   U13-Forward    6 年前

    diff numpy方法:

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

    打电话给:

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

    True
    
        20
  •  2
  •   Luis B    6 年前

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

    打电话给:

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

    输出:

    是的

        21
  •  1
  •   ninjagecko    12 年前

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

    python让您导入像 operator.and_ . 从python3开始,您还需要导入 functools.reduce .

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

        22
  •  1
  •   berdario    10 年前
    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)))
    
        23
  •  1
  •   Lumo5    7 年前

    将列表更改为集合。如果集合的大小只有1,那么它们一定是相同的。

    if len(set(my_list)) == 1:
    
        24
  •  1
  •   Foad S. Farimani    6 年前

    还有一个纯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 .

        25
  •  0
  •   Saeed    5 年前

    你可以用 .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
  •   Anatoly Scherbakov    5 年前

    你可以用 set

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

    例子:

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