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

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

Вход : list

Выход :

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

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

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

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

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


EDIT :

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

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

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

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

  • Удалить цифры в Python (Regex)
  • Python sys.stdin.read (max) до тех пор, пока не будет прочитано max (если max> = 0), блокирует до EOF else, но select указывает, что есть данные для чтения
  • Одна строка if-condition-assign
  • Может ли этот интерпретатор нотации Postfix нотации (обратный лак) Python быть более эффективным и точным?
  • Python - AttributeError: объект «NoneType» не имеет атрибута «findAll»
  • Как передать объект в сборку мусора python?
  • Удаление элемента из очереди приоритетов
  • Как запустить интерпретатор python в Emacs?
  • 19 Solutions collect form web for “проверьте, идентичны ли все элементы в списке”

    Общий метод:

     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 is b вместо a == 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 

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

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

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

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

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

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

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

    это должно работать:

    len(set(the_list))==1

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

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

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

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

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

    Сомневаюсь, что это «самый 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 

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

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

     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 .

    Если вам интересно что-то более читаемое (но, конечно, не так эффективно), вы можете попробовать:

     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 

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

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

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

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

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

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

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

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

    np.allclose(array, array[0])

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

     lst = [1,1,1,1,1,1,1,1,1] print all(map(lambda x: x == lst[0], lst[1:])) 
     >>> 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" 

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

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

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

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

     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))) 
    Python - лучший язык программирования в мире.