Was ist ein effizienter Weg, um das häufigste Element in einer Python-Liste zu finden?
Meine Listenelemente sind möglicherweise nicht hashbar und können daher kein Wörterbuch verwenden. Auch bei Ziehungen sollte der Artikel mit dem niedrigsten Index zurückgegeben werden. Beispiel:
>>> most_common(['duck', 'duck', 'goose'])
'duck'
>>> most_common(['goose', 'duck', 'duck', 'goose'])
'goose'
Antworten:
Bei so vielen vorgeschlagenen Lösungen bin ich erstaunt, dass niemand vorgeschlagen hat, was ich für offensichtlich halte (für nicht hashbare, aber vergleichbare Elemente) - [
itertools.groupby
] [1].itertools
bietet schnelle, wiederverwendbare Funktionen und ermöglicht es Ihnen, einige knifflige Logik an bewährte Standardbibliothekskomponenten zu delegieren. Betrachten Sie zum Beispiel:Dies könnte natürlich präziser geschrieben werden, aber ich strebe nach maximaler Klarheit. Die beiden
print
Aussagen können unkommentiert werden, um die Maschinerie in Aktion besser zu sehen. Zum Beispiel mit unkommentierten Abzügen:emittiert:
Wie Sie sehen,
SL
handelt es sich um eine Liste von Paaren, wobei jedes Paar ein Element gefolgt vom Index des Elements in der ursprünglichen Liste ist (um die Schlüsselbedingung zu implementieren, dass das Ergebnis sein muss, wenn die "häufigsten" Elemente mit derselben höchsten Anzahl> 1 sind am frühesten auftreten).groupby
Gruppen nur nach Artikel (viaoperator.itemgetter
). Die Hilfsfunktion, die während dermax
Berechnung einmal pro Gruppierung aufgerufen wird , empfängt und entpackt intern eine Gruppe - ein Tupel mit zwei Elementen,(item, iterable)
wobei die Elemente des Iterables auch Tupel mit zwei Elementen sind,(item, original index)
[[die Elemente vonSL
]].Dann verwendet die Hilfsfunktion eine Schleife, um sowohl die Anzahl der Einträge in der iterierbaren Gruppe als auch den minimalen ursprünglichen Index zu bestimmen . Diese werden als kombinierter "Qualitätsschlüssel" zurückgegeben, wobei das Vorzeichen des Min-Index geändert wird, sodass die
max
Operation die Elemente berücksichtigt, die zuvor in der ursprünglichen Liste aufgetreten sind.Dieser Code könnte viel einfacher sein, wenn er sich ein wenig weniger Gedanken über Big-O-Probleme in Zeit und Raum macht, z. B.::
Dieselbe Grundidee, nur einfacher und kompakter ausgedrückt ... aber leider ein zusätzlicher O (N) -Hilfsraum (um die Iterablen der Gruppen in Listen zu verkörpern) und O (N-Quadrat) -Zeit (um die
L.index
von jedem Element zu erhalten) . Während vorzeitige Optimierung die Wurzel allen Übels in der Programmierung ist, widerspricht die bewusste Auswahl eines O (N-Quadrat) -Ansatzes, wenn ein O (N log N) verfügbar ist, einfach zu sehr der Skalierbarkeit! -)Für diejenigen, die "Oneliners" gegenüber Klarheit und Leistung bevorzugen, eine Bonus-1-Liner-Version mit entsprechend verstümmelten Namen :-).
quelle
groupby
erfordert zuerst eine Sortierung (O (NlogN)); Die Verwendung einesCounter()
withmost_common()
kann dies übertreffen, da ein Heapq verwendet wird, um das Element mit der höchsten Frequenz zu finden (für nur 1 Element entspricht dies der O (N) -Zeit). Da esCounter()
jetzt stark optimiert ist (das Zählen erfolgt in einer C-Schleife), kann es diese Lösung auch für kleine Listen leicht übertreffen. Es bläst es für große Listen aus dem Wasser.Ein einfacher Einzeiler:
quelle
set(lst)
muss die gesamte Liste erneut überprüft werden)… Wahrscheinlich jedoch schnell genug für die meisten Anwendungen…set(lst)
mitlst
und es wird auch mit nicht-hashable Elementen arbeiten; wenn auch langsamer.list.count()
muss die Liste vollständig durchlaufen , und Sie tun dies für jedes einzelne eindeutige Element in der Liste. Dies macht dies zu einer O (NK) -Lösung (O (N ^ 2) im schlimmsten Fall). Die Verwendung von aCounter()
dauert nur O (N)!Ausgeliehen von hier , kann dies mit Python 2.7 verwendet werden:
Arbeitet ungefähr 4-6 mal schneller als Alex 'Lösungen und ist 50 mal schneller als der von newacct vorgeschlagene Einzeiler.
So rufen Sie das Element ab, das bei Bindungen zuerst in der Liste vorkommt:
quelle
most_common
ist nach Anzahl sortiert, nicht ungeordnet. Das heißt, es wird nicht das erste Element bei Unentschieden auswählen; Ich habe eine andere Möglichkeit hinzugefügt, den Zähler zu verwenden, der das erste Element auswählt.Was Sie wollen, wird in der Statistik als Modus bezeichnet, und Python verfügt natürlich über eine integrierte Funktion, die genau das für Sie erledigt:
Beachten Sie, dass, wenn es kein "häufigstes Element" gibt, wie z. B. Fälle, in denen die beiden obersten verknüpft sind , dies erhöht wird
StatisticsError
, da statistisch gesehen in diesem Fall kein Modus vorhanden ist .quelle
set
und ist plausibelO(n^3)
.Wenn sie nicht hashbar sind, können Sie sie sortieren und eine einzelne Schleife über das Ergebnis durchführen, wobei die Elemente gezählt werden (identische Elemente werden nebeneinander angezeigt). Aber es könnte schneller sein, sie hashbar zu machen und ein Diktat zu verwenden.
quelle
Counter()
LösungDies ist eine O (n) -Lösung.
(Umgekehrt wird verwendet, um sicherzustellen, dass das niedrigste Indexelement zurückgegeben wird.)
quelle
Sortieren Sie eine Kopie der Liste und finden Sie die längste Laufzeit. Sie können die Liste dekorieren, bevor Sie sie mit dem Index jedes Elements sortieren, und dann den Lauf auswählen, der bei einem Gleichstand mit dem niedrigsten Index beginnt.
quelle
Ohne die Anforderung des niedrigsten Index können Sie Folgendes verwenden
collections.Counter
:quelle
Ein Einzeiler:
quelle
quelle
Einfache einzeilige Lösung
Es wird das häufigste Element mit seiner Frequenz zurückgeben.
quelle
Sie brauchen das wahrscheinlich nicht mehr, aber das habe ich für ein ähnliches Problem getan. (Es sieht länger aus als es wegen der Kommentare ist.)
quelle
Aufbauend auf Luiz 'Antwort , aber erfüllt die Bedingung " Im Falle von Ziehungen sollte der Artikel mit dem niedrigsten Index zurückgegeben werden ":
Beispiel:
quelle
Hier:
Ich habe das vage Gefühl, dass es irgendwo in der Standardbibliothek eine Methode gibt, mit der Sie die Anzahl der einzelnen Elemente angeben können, aber ich kann sie nicht finden.
quelle
Dies ist die offensichtlich langsame Lösung (O (n ^ 2)), wenn weder Sortieren noch Hashing möglich sind, aber ein Gleichheitsvergleich (
==
) verfügbar ist:Wenn Sie Ihre Elemente jedoch hashbar oder sortierbar machen (wie in anderen Antworten empfohlen), wird das häufigste Element fast immer schneller gefunden, wenn die Länge Ihrer Liste (n) groß ist. O (n) im Durchschnitt mit Hashing und O (n * log (n)) im schlimmsten Fall zum Sortieren.
quelle
quelle
Ich musste dies in einem kürzlich durchgeführten Programm tun. Ich gebe es zu, ich konnte Alex 'Antwort nicht verstehen, also habe ich das erreicht.
Ich habe es mit Alex 'Lösung verglichen und es ist ungefähr 10-15% schneller für kurze Listen, aber sobald Sie über 100 Elemente oder mehr gehen (getestet bis 200000), ist es ungefähr 20% langsamer.
quelle
Hallo, das ist eine sehr einfache Lösung mit großem O (n)
Wobei das Element in der Liste nummeriert wird, das sich die meiste Zeit wiederholt
quelle
quelle
quelle
quelle