Мне нужна следующая функция:
Вход : аlist
Выход :
True
если все элементы входного списка оцениваются как равные друг другу, используя стандартный оператор равенства;False
в противном случае.
Производительность : конечно, я предпочитаю не подвергаться ненужным накладным расходам.
Я чувствую, что было бы лучше:
- перебрать список
- сравнить соседние элементы
- и
AND
все полученные логические значения
Но я не уверен, какой самый Pythonic способ сделать это.
Отсутствие функции короткого замыкания сказывается только на длинном входе (более ~ 50 элементов), который имеет неравные элементы в начале. Если это происходит достаточно часто (как часто зависит от длины списков), короткое замыкание не требуется. Лучший алгоритм короткого замыкания, кажется, @KennyTM checkEqual1
. Это платит, однако, значительную стоимость для этого:
- почти в 20 раз по производительности почти одинаковые списки
- производительность до 2,5 раз в коротких списках
Если длинные входы с ранними неравными элементами не происходят (или случаются достаточно редко), короткое замыкание не требуется. Тогда, безусловно, самым быстрым является решение @Ivo van der Wijk.
источник
a == b
или идентичный как вa is b
?functools.reduce(operator.eq, a)
что не было предложено.Ответы:
Общий метод:
Один лайнер:
Также однострочник:
Разница между 3 версиями заключается в том, что:
checkEqual2
содержанию должен быть хэшcheckEqual1
иcheckEqual2
может использовать любые итераторы, ноcheckEqual3
должен принимать последовательность ввода, обычно это конкретные контейнеры, такие как список или кортеж.checkEqual1
останавливается, как только разница обнаружена.checkEqual1
содержит больше кода Python, он менее эффективен, когда многие элементы равны в начале.checkEqual2
иcheckEqual3
всегда выполняйте O (N) операции копирования, они займут больше времени, если большая часть вашего ввода вернет False.checkEqual2
иcheckEqual3
сложнее адаптировать сравнениеa == b
кa is b
.timeit
результат, для Python 2.7 и (только s1, s4, s7, s9 должны возвращать True)мы получили
Замечания:
источник
obj.__eq__
когда»lhs is rhs
, и неупорядоченные оптимизации для более быстрого замыкания отсортированных списков.itertools
рецепт, который я добавил в качестве ответа. Возможно, стоит добавить это в вашу временную матрицу :-).Решение, которое быстрее, чем использование set (), которое работает с последовательностями (а не итерациями), состоит в простом подсчете первого элемента. Предполагается, что список не пуст (но это легко проверить и решить, каким должен быть результат в пустом списке).
несколько простых тестов:
источник
x.count(next(x)) == len(x)
так, чтобы он работал для любого контейнера х? Аааа .. НМ, только что увидел, что .count доступен только для последовательностей. Почему он не реализован для других встроенных контейнеров? Является ли подсчет внутри словаря по сути менее значимым, чем внутри списка?count
не реализован для итераторов, а не почемуlen
не доступен для итераторов. Ответ, вероятно, в том, что это просто недосмотр. Но это неважно для нас, потому что по умолчанию.count()
для последовательностей очень медленно (чистый питон). Причина, по которой ваше решение настолько быстрое, заключается в том, что оно опирается на C-внедренный,count
предоставленныйlist
. Так что я полагаю, что любая итеративная реализацияcount
метода в C выиграет от вашего подхода.Самый простой и элегантный способ заключается в следующем:
(Да, это работает даже с пустым списком! Это потому, что это один из немногих случаев, когда у python ленивая семантика.)
Что касается производительности, то это не удастся в самое ближайшее время, поэтому она асимптотически оптимальна.
источник
checkEqual1
. Я не уверен почему.first=myList[0]
all(x==first for x in myList)
, возможноfirst=myList[0]
выдаетIndexError
пустой список, поэтому комментаторам, которые говорили об этой оптимизации, о которой я упоминал, придется иметь дело с крайним случаем пустого списка. Тем не менее, оригинал в порядке (x==myList[0]
в порядке,all
потому что он никогда не оценивается, если список пуст).Набор сравнительных работ:
Использование
set
удаляет все дубликаты элементов.источник
Вы можете преобразовать список в набор. Набор не может иметь дубликатов. Таким образом, если все элементы в исходном списке идентичны, в наборе будет только один элемент.
источник
len(set(input_list)) == 1
?Для чего это стоит, это недавно появилось в списке рассылки python-ideas . Оказывается, что для этого уже есть рецепт itertools : 1
Предположительно, он работает очень хорошо и имеет несколько хороших свойств.
1 Другими словами, я не могу взять кредит за то, что нашел решение - и я не могу взять кредит за то, что даже нашел его.
источник
return next(g, f := next(g, g)) == f
(из py3.8 конечно)Вот два простых способа сделать это
используя set ()
При преобразовании списка в набор дублирующиеся элементы удаляются. Таким образом, если длина преобразованного набора равна 1, то это означает, что все элементы одинаковы.
Вот пример
используя все ()
Это позволит сравнить (эквивалентность) первого элемента входного списка с каждым другим элементом в списке. Если все эквивалентны True, будет возвращено, в противном случае False будет возвращено.
Вот пример
PS Если вы проверяете, является ли весь список эквивалентным определенному значению, вы можете выбрать значение для input_list [0].
источник
len(set(a))
списка из 10 000 000 элементов заняло 0,09 с, тогда как выполнениеall
заняло 0,9 с (в 10 раз дольше).Это еще один вариант, более быстрый, чем
len(set(x))==1
для длинных списков (использует короткое замыкание)источник
Это простой способ сделать это:
Это немного сложнее, это вызывает накладные расходы при вызове функций, но семантика более четко прописана:
источник
for elem in mylist[1:]
. Сомневаюсь, что это значительно повышает скорость, хотя, как я полагаю,elem[0] is elem[0]
переводчик, вероятно, сможет сделать это сравнение очень быстро.Проверьте, все ли элементы равны первому.
np.allclose(array, array[0])
источник
Сомневаюсь, что это «самый Pythonic», но что-то вроде:
сделал бы трюк.
источник
for
цикл может быть сделан более Pythonicif any(item != list[0] for item in list[1:]): return False
, с точно такой же семантикой.Если вы заинтересованы в чем-то более читабельном (но, конечно, не столь эффективном), вы можете попробовать:
источник
Преобразуйте список в набор, а затем найдите количество элементов в наборе. Если результат равен 1, он имеет идентичные элементы, а если нет, то элементы в списке не идентичны.
источник
Что касается использования
reduce()
сlambda
. Вот рабочий код, который я лично считаю намного лучше, чем некоторые другие ответы.Возвращает кортеж, в котором первое значение является логическим, если все элементы одинаковы или нет.
источник
[1, 2, 2]
): он не учитывает предыдущее логическое значение. Это можно исправить, заменивx[1] == y
наx[0] and x[1] == y
.Я сделаю:
as
any
прекращает поиск итерируемого, как только находитTrue
условие.источник
all()
почему бы не использоватьall(x == seq[0] for x in seq)
? выглядит более питоническим и должен выполнять то же самоеисточник
Работает в Python 2.4, который не имеет «все».
источник
for k in j: break
эквивалентноnext(j)
. Вы могли бы также сделать,def allTheSame(x): return len(list(itertools.groupby(x))<2)
если бы вы не заботились об эффективности.Можно использовать карту и лямбду
источник
Или используйте
diff
метод NumPy:И позвонить:
Вывод:
источник
not np.any(np.diff(l))
может быть немного быстрее.Или используйте метод сравнения numpy:
И позвонить:
Вывод:
Правда
источник
Ты можешь сделать:
Довольно досадно, что python заставляет вас импортировать операторы как
operator.and_
. Начиная с python3, вам нужно будет также импортироватьfunctools.reduce
.(Вы не должны использовать этот метод, потому что он не сломается, если он найдет неравные значения, но продолжит изучение всего списка. Он просто включен здесь как ответ на полноту.)
источник
Следующее закоротит короткое замыкание:
источник
reduce(lambda a,b:a==b, [2,2,2])
доходностьFalse
... Я его отредактировал, но теперь это уже не красивоИзмените список на набор. Тогда, если размер набора только 1, они должны быть одинаковыми.
источник
Существует также рекурсивная опция чистого Python:
Однако по некоторым причинам это в некоторых случаях на два порядка медленнее, чем другие варианты. Исходя из менталитета языка Си, я ожидал, что это будет быстрее, но это не так!
Другим недостатком является то, что в Python есть предел рекурсии, который в этом случае необходимо скорректировать. Например, используя это .
источник
Вы можете использовать,
.nunique()
чтобы найти количество уникальных предметов в списке.источник
Вы можете использовать
set
. Это сделает набор и удалит повторяющиеся элементы. Затем убедитесь, что в нем не более 1 элемента.Пример:
источник