Quel est le moyen efficace de trouver l'élément le plus courant dans une liste Python?
Les éléments de ma liste peuvent ne pas être hachables et je ne peux donc pas utiliser de dictionnaire. Aussi en cas de tirages, l'élément avec l'indice le plus bas doit être retourné. Exemple:
>>> most_common(['duck', 'duck', 'goose'])
'duck'
>>> most_common(['goose', 'duck', 'duck', 'goose'])
'goose'
Réponses:
Avec autant de solutions proposées, je suis étonné que personne n'ait proposé ce que je considérerais comme évident (pour des éléments non hachables mais comparables) - [
itertools.groupby
] [1].itertools
offre des fonctionnalités rapides et réutilisables et vous permet de déléguer une logique délicate à des composants de bibliothèque standard bien testés. Considérez par exemple:Cela pourrait être écrit de manière plus concise, bien sûr, mais je vise une clarté maximale. Les deux
print
déclarations peuvent être décommentées pour mieux voir le mécanisme en action; par exemple, avec des impressions non commentées:émet:
Comme vous le voyez,
SL
est une liste de paires, chaque paire un élément suivi de l'index de l'élément dans la liste d'origine (pour implémenter la condition clé selon laquelle, si les éléments "les plus courants" avec le même nombre le plus élevé sont> 1, le résultat doit être le plus ancien).groupby
groupes par élément uniquement (viaoperator.itemgetter
). La fonction auxiliaire, appelée une fois par regroupement pendant lemax
calcul, reçoit et décompresse en interne un groupe - un tuple avec deux éléments(item, iterable)
où les éléments de l'itérable sont également des tuples à deux éléments,(item, original index)
[[les éléments deSL
]].Ensuite, la fonction auxiliaire utilise une boucle pour déterminer à la fois le nombre d'entrées dans l'itérable du groupe et l'index d'origine minimum; il renvoie ceux-ci sous forme de «clé de qualité» combinée, avec le signe d'index min modifié de sorte que l'
max
opération considère «meilleurs» les éléments qui se sont produits plus tôt dans la liste d'origine.Ce code pourrait être beaucoup plus simple s'il s'inquiétait un peu moins des grands problèmes de temps et d'espace, par exemple ...:
même idée de base, juste exprimée plus simplement et de manière plus compacte ... mais, hélas, un espace auxiliaire O (N) supplémentaire (pour incarner les itérables des groupes dans les listes) et le temps O (N au carré) (pour obtenir le
L.index
de chaque élément) . Alors que l'optimisation prématurée est la racine de tous les maux de la programmation, choisir délibérément une approche O (N au carré) lorsqu'une O (N log N) est disponible va trop à l'encontre de l'évolutivité! -)Enfin, pour ceux qui préfèrent les "oneliners" à la clarté et à la performance, une version bonus 1-liner avec des noms convenablement mutilés :-).
la source
groupby
nécessite un tri en premier (O (NlogN)); utiliser unCounter()
avecmost_common()
peut battre cela car il utilise un heapq pour trouver l'élément de fréquence la plus élevée (pour seulement 1 élément, c'est le temps O (N)). CommeCounter()
maintenant est fortement optimisé (le comptage a lieu dans une boucle C), il peut facilement battre cette solution même pour les petites listes. Il le souffle hors de l'eau pour les grandes listes.Un one-liner plus simple:
la source
set(lst)
, la liste entière doit être vérifiée à nouveau)… Probablement assez rapide pour la plupart des utilisations, cependant…set(lst)
parlst
et cela fonctionnera également avec des éléments non hachables; quoique plus lent.list.count()
doit parcourir la liste dans son intégralité , et vous le faites pour chaque élément unique de la liste. Cela en fait une solution O (NK) (O (N ^ 2) dans le pire des cas). L'utilisation de aCounter()
ne prend qu'un temps O (N)!Emprunt à partir d' ici , cela peut être utilisé avec Python 2.7:
Fonctionne 4 à 6 fois plus vite que les solutions d'Alex et est 50 fois plus rapide que le one-liner proposé par newacct.
Pour récupérer l'élément qui apparaît en premier dans la liste en cas d'égalité:
la source
most_common
est trié par nombre et non par ordre. Cela dit, il ne choisira pas le premier élément en cas d'égalité; J'ai ajouté une autre façon d'utiliser le compteur qui sélectionne le premier élément.Ce que vous voulez est connu dans les statistiques sous le nom de mode, et Python a bien sûr une fonction intégrée pour faire exactement cela pour vous:
Notez que s'il n'y a pas d '«élément le plus commun» comme les cas où les deux premiers sont à égalité , cela augmentera
StatisticsError
, car statistiquement parlant, il n'y a pas de mode dans ce cas.la source
set
, et est plausibleO(n^3)
.S'ils ne sont pas hachables, vous pouvez les trier et faire une seule boucle sur le résultat en comptant les éléments (les éléments identiques seront côte à côte). Mais il peut être plus rapide de les rendre hachables et d'utiliser un dict.
la source
Counter()
solution d'AlexCeci est une solution O (n).
(inversé est utilisé pour s'assurer qu'il renvoie l'élément d'index le plus bas)
la source
Sans l'exigence relative à l'indice le plus bas, vous pouvez utiliser
collections.Counter
pour cela:la source
Triez une copie de la liste et recherchez la plus longue série. Vous pouvez décorer la liste avant de la trier avec l'index de chaque élément, puis choisir la séquence qui commence par l'index le plus bas en cas d'égalité.
la source
Un one-liner:
la source
la source
Solution simple en une ligne
Il renverra l'élément le plus fréquent avec sa fréquence.
la source
Vous n'en avez probablement plus besoin, mais c'est ce que j'ai fait pour un problème similaire. (Il a l'air plus long qu'à cause des commentaires.)
la source
En s'appuyant sur la réponse de Luiz , mais en remplissant la condition " en cas de tirage au sort, l'élément avec l'indice le plus bas doit être retourné ":
Exemple:
la source
Ici:
J'ai un vague sentiment qu'il existe une méthode quelque part dans la bibliothèque standard qui vous donnera le décompte de chaque élément, mais je ne la trouve pas.
la source
C'est la solution lente évidente (O (n ^ 2)) si ni le tri ni le hachage ne sont possibles, mais la comparaison d'égalité (
==
) est disponible:Mais rendre vos éléments hachables ou triables (comme recommandé par d'autres réponses) permettrait presque toujours de trouver l'élément le plus courant plus rapidement si la longueur de votre liste (n) est grande. O (n) en moyenne avec hachage, et O (n * log (n)) au pire pour le tri.
la source
la source
J'avais besoin de le faire dans un programme récent. Je l'admets, je n'ai pas pu comprendre la réponse d'Alex, c'est donc ce avec quoi j'ai fini.
Je l'ai chronométré par rapport à la solution d'Alex et c'est environ 10 à 15% plus rapide pour les listes courtes, mais une fois que vous dépassez 100 éléments ou plus (testé jusqu'à 200 000), c'est environ 20% plus lent.
la source
Salut c'est une solution très simple avec gros O (n)
Où numéroter l'élément de la liste qui se répète la plupart du temps
la source
la source
la source
la source