Проверьте, идентичны ли все элементы в списке

Мне нужна следующая функция:

Вход: a list

Выход:

  • True, если все элементы в списке ввода оцениваются как равные друг другу с помощью стандартного оператора равенства;
  • False в противном случае.

Производительность: конечно, я предпочитаю не налагать лишних накладных расходов.

Я считаю, что было бы лучше:

  • итерация по списку
  • сравнить соседние элементы
  • и AND все полученные булевы значения

Но я не уверен, какой самый питонический способ сделать это.


ИЗМЕНИТЬ

Спасибо за все замечательные ответы. Я оценил несколько, и было очень сложно выбирать между решениями @KennyTM и @Ivo van der Wijk.

Недостаток функции короткого замыкания болит только на длинном входе (более ~ 50 элементов), которые на ранних этапах имеют неравные элементы. Если это происходит достаточно часто (как часто зависит от того, как долго могут быть списки), требуется короткое замыкание. Лучшим алгоритмом короткого замыкания является @KennyTM checkEqual1. Тем не менее, это требует значительных затрат:

  • до 20x в производительности почти идентичные списки
  • до 2,5x в производительности в коротких списках

Если длинные входы с ранними неравными элементами не происходят (или происходят достаточно редко), короткое замыкание не требуется. Тогда самым быстрым решением является @Ivo van der Wijk.

Ответ 1

Общий метод:

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 и checkEqual2 могут использовать любые итераторы, но checkEqual3 должен принимать ввод последовательности, обычно конкретные контейнеры, такие как список или кортеж.
  3. checkEqual1 останавливается, как только обнаруживается разница.
  4. Так как checkEqual1 содержит больше кода Python, он менее эффективен, когда многие из элементов равны в начале.
  5. Поскольку checkEqual2 и checkEqual3 всегда выполняют операции копирования O (N), они будут занимать больше времени, если большая часть вашего ввода вернет False.
  6. Для checkEqual2 и checkEqual3 сложнее адаптировать сравнение от a == b к a 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

Ответ 2

Решение быстрее, чем использование 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

Ответ 3

Самый простой и самый элегантный способ заключается в следующем:

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

(Да, это работает даже с пустым списком! Это потому, что это один из немногих случаев, когда у python ленивая семантика.)

Что касается производительности, то это не удастся в самое ближайшее время, поэтому она асимптотически оптимальна.

Ответ 4

Сложная сравнительная работа:

len(set(the_list)) == 1

Использование set удаляет все повторяющиеся элементы.

Ответ 5

Вы можете преобразовать список в набор. У набора не может быть дубликатов. Поэтому, если все элементы в исходном списке идентичны, набор будет иметь только один элемент.

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

Ответ 6

Для чего это стоит, недавно появилось в список рассылки python-идей. Оказывается, что для этого уже существует 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)

Предположительно, он работает очень хорошо и имеет несколько приятных свойств.

  • Короткие замыкания: он перестанет потреблять элементы из итерируемого, как только он найдет первый неравный элемент.
  • Не требует, чтобы элементы были хешируемыми.
  • Он ленив и требует только O (1) дополнительной памяти для проверки.

1 Другими словами, я не могу взять на себя ответственность за то, чтобы придумать решение - и я не могу взять на себя ответственность за его поиск.

Ответ 7

Вот два простых способа сделать это

используя 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

используя все()

Это будет сравнивать (эквивалентность) первый элемент входного списка с каждым другим элементом в списке. Если все эквиваленты 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

PS Если вы проверяете, соответствует ли весь список определенному значению, вы можете suibstitue значение для input_list [0].

Ответ 8

Это еще один вариант, более быстрый, чем len(set(x))==1 для длинных списков (используется короткое замыкание)

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

Ответ 9

Это простой способ сделать это:

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

Убедитесь, что все элементы равны первому.

np.allclose(array, array[0])

Ответ 11

Сомнительно, что это "самый 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

сделал бы трюк.

Ответ 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

Я бы сделал:

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

as any останавливает поиск итерации, как только находит условие True.

Ответ 14

Относительно использования reduce() с lambda. Вот рабочий код, который я лично считаю более приятным, чем некоторые другие ответы.

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

Возвращает truple, где первое значение является логическим, если все элементы одинаковы или нет.

Ответ 15

Преобразуйте список в набор, а затем найдите количество элементов в наборе. Если результат равен 1, он имеет одинаковые элементы, а если нет, то элементы в списке не идентичны.

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

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

Ответ 16

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

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

Работает в Python 2.4, у которого нет "всех".

Ответ 18

Можно использовать карту и лямбда

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

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

Ответ 19

Или используйте метод diff numpy:

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

И позвонить:

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

Выход:

True

Ответ 20

Или используйте метод сравнения numpy:

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

И позвонить:

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

Выход:

Правда

Ответ 21

Вы можете сделать:

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

Довольно раздражает, что python заставляет вас импортировать операторы типа operator.and_. Начиная с python3 вам также потребуется импортировать functools.reduce.

(Вы не должны использовать этот метод, потому что он не будет ломаться, если он найдет не равные значения, но продолжит рассмотрение всего списка. Он просто включен здесь в качестве ответа для полноты.)

Ответ 22

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, они должны быть одинаковыми.

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

Ответ 24

Существует также рекурсивная опция чистого Python:

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

Однако по некоторым причинам он в некоторых случаях на два порядка медленнее, чем другие варианты. Исходя из менталитета языка Си, я ожидал, что это будет быстрее, но это не так!

Другим недостатком является то, что в Python есть предел рекурсии, который в этом случае необходимо отрегулировать. Например, используя это.

Ответ 25

Вы можете использовать .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

Вы можете использовать set это сделает набор и удалит повторяющиеся элементы. затем проверьте, имеет ли он 1 элемент.

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