Какой эффективный способ найти наиболее распространенный элемент в списке Python?
Элементы моего списка не могут быть хэшируемыми, поэтому не могут использовать словарь. Также в случае розыгрышей должен быть возвращен предмет с самым низким индексом. Пример:
>>> most_common(['duck', 'duck', 'goose'])
'duck'
>>> most_common(['goose', 'duck', 'duck', 'goose'])
'goose'
Ответы:
С таким количеством предложенных решений, я удивлен, что никто не предложил то, что я считаю очевидным (для не хэшируемых, но сопоставимых элементов) - [
itertools.groupby
] [1].itertools
предлагает быструю, многократно используемую функциональность и позволяет делегировать некоторую сложную логику хорошо протестированным стандартным компонентам библиотеки. Рассмотрим для примера:Конечно, это можно написать более кратко, но я стремлюсь к максимальной ясности. Эти два
print
утверждения могут быть прокомментированы, чтобы лучше увидеть механизм в действии; например, с отпечатками без комментариев:излучает:
Как видите,
SL
это список пар, каждая пара которых представляет элемент, за которым следует индекс элемента в исходном списке (для реализации ключевого условия, согласно которому, если «наиболее распространенные» элементы с одинаковым наибольшим числом> 1, результат должен быть самым первым встречающимся).groupby
группирует только по пункту (черезoperator.itemgetter
). Вспомогательная функция, вызываемая один раз для каждой группы во времяmax
вычисления, получает и внутренне распаковывает группу - кортеж с двумя элементами,(item, iterable)
где элементы итерируемого объекта также являются кортежами из двух элементов,(item, original index)
[[items ofSL
]].Затем вспомогательная функция использует цикл для определения количества записей в итерируемой группе и минимального исходного индекса; он возвращает их как объединенный «ключ качества» с измененным знаком мин индекса, поэтому
max
операция будет считать «лучше» те элементы, которые встречались ранее в исходном списке.Этот код мог бы быть намного проще, если бы он немного меньше беспокоился о проблемах больших объемов во времени и пространстве, например ...:
та же самая основная идея, просто выраженная более просто и компактно ... но, увы, дополнительное O (N) вспомогательное пространство (для включения элементов групп в списки) и O (N в квадрате) время (для получения
L.index
каждого элемента) , В то время как преждевременная оптимизация является корнем всего зла в программировании, преднамеренный выбор подхода O (N в квадрате), когда O (N log N) один, просто слишком сильно противоречит масштабируемости! -)Наконец, для тех, кто предпочитает «oneliners» ясности и производительности, бонусная версия с 1 вкладышем с соответствующим образом искаженными именами :-).
источник
groupby
сначала требуется сортировка (O (NlogN)); использованиеCounter()
withmost_common()
может превзойти это, поскольку он использует heapq для поиска элемента с самой высокой частотой (только для 1 элемента это время O (N)). ПосколькуCounter()
сейчас он сильно оптимизирован (подсчет происходит в цикле C), он может легко превзойти это решение даже для небольших списков. Это выдувает это из воды для больших списков.Более простой однострочник:
источник
set(lst)
, весь список должен быть проверен еще раз) ... Вероятно, достаточно быстро для большинства применений, хотя ...set(lst)
на,lst
и это также будет работать с не хэш-элементами; хотя и медленнее.list.count()
должен пройти список полностью , и вы делаете это для каждого уникального элемента в списке. Это делает это решение O (NK) (O (N ^ 2) в худшем случае). ИспользованиеCounter()
только занимает O (N) время!Заимствуя отсюда , это может использоваться с Python 2.7:
Работает примерно в 4-6 раз быстрее, чем решения Alex, и в 50 раз быстрее, чем однострочный, предложенный newacct.
Чтобы получить элемент, который появляется первым в списке в случае связей:
источник
most_common
отсортировано по количеству, а не по порядку. Тем не менее, он не выберет первый элемент в случае связей; Я добавил еще один способ использования счетчика, который выбирает первый элемент.То, что вы хотите, в статистике называется режимом, и, конечно, в Python есть встроенная функция, которая сделает это именно за вас:
Обратите внимание, что если нет «самого распространенного элемента», например, в случаях, когда два верхних элемента связаны , то это повысится
StatisticsError
, потому что, по статистике, в этом случае нет режима .источник
set
и правдоподобноO(n^3)
.Если они не могут быть хешируемыми, вы можете отсортировать их и сделать один цикл по результату, подсчитывая элементы (идентичные элементы будут рядом друг с другом). Но может быть быстрее сделать их хэшированными и использовать диктовку.
источник
Counter()
решением АлексаЭто решение O (n).
(обратный используется, чтобы убедиться, что он возвращает элемент с наименьшим индексом)
источник
Без требования о самом низком индексе вы можете использовать
collections.Counter
для этого:источник
Сортируйте копию списка и найдите самый длинный пробег. Вы можете украсить список перед сортировкой по индексу каждого элемента, а затем выбрать прогон, который начинается с самого низкого индекса в случае связи.
источник
Однострочник:
источник
источник
Простое решение в одну строку
Он вернет наиболее частый элемент с его частотой.
источник
Возможно, вам это больше не нужно, но это то, что я сделал для аналогичной проблемы. (Это выглядит дольше, чем из-за комментариев.)
источник
Основываясь на ответе Луиса , но удовлетворяя условию « в случае ничьих, должен быть возвращен элемент с самым низким индексом »:
Пример:
источник
Вот:
У меня есть смутное ощущение, что где-то в стандартной библиотеке есть метод, который даст вам счетчик каждого элемента, но я не могу его найти.
источник
Это очевидное медленное решение (O (n ^ 2)), если ни сортировка, ни хеширование не осуществимы, но
==
доступно сравнение на равенство ( ):Но если сделать ваши элементы хэшируемыми или сортируемыми (как рекомендовано другими ответами), почти всегда будет быстрее найти самый распространенный элемент, если длина вашего списка (n) велика. O (n) в среднем с хэшированием и O (n * log (n)) в худшем случае для сортировки.
источник
источник
Мне нужно было сделать это в недавней программе. Я признаю это, я не мог понять ответ Алекса, так что это то, чем я закончил.
Я сравнил его с решением Алекса, и он работает на 10-15% быстрее для коротких списков, но если вы наберете более 100 элементов (проверено до 200000), это примерно на 20% медленнее.
источник
Привет, это очень простое решение с большим O (n)
Где номер элемента в списке, который повторяется большую часть времени
источник
источник
источник
источник