¿Cuál es una forma eficiente de encontrar el elemento más común en una lista de Python?
Es posible que los elementos de mi lista no se puedan compartir, así que no puedo usar un diccionario. También en caso de sorteos, se debe devolver el artículo con el índice más bajo. Ejemplo:
>>> most_common(['duck', 'duck', 'goose'])
'duck'
>>> most_common(['goose', 'duck', 'duck', 'goose'])
'goose'
Respuestas:
Con tantas soluciones propuestas, me sorprende que nadie haya propuesto lo que yo consideraría obvio (para elementos no intercambiables pero comparables) - [
itertools.groupby
] [1].itertools
ofrece una funcionalidad rápida y reutilizable, y le permite delegar algunas lógicas difíciles a componentes de biblioteca estándar bien probados Considere por ejemplo:Esto podría escribirse de manera más concisa, por supuesto, pero estoy buscando la máxima claridad. Las dos
print
declaraciones pueden ser descomentadas para ver mejor la maquinaria en acción; por ejemplo, con impresiones sin comentar:emite:
Como puede ver,
SL
es una lista de pares, cada par un elemento seguido del índice del elemento en la lista original (para implementar la condición clave de que, si los elementos "más comunes" con el mismo recuento más alto son> 1, el resultado debe ser el más temprano).groupby
agrupa por el artículo solamente (víaoperator.itemgetter
). La función auxiliar, llamada una vez por agrupación durante elmax
cálculo, recibe y desempaqueta internamente un grupo: una tupla con dos elementos(item, iterable)
donde los elementos del iterable también son tuplas de dos elementos,(item, original index)
[[los elementos deSL
]].Luego, la función auxiliar utiliza un bucle para determinar tanto el recuento de entradas en el iterable del grupo como el índice original mínimo; los devuelve como "clave de calidad" combinada, con el signo de índice mínimo cambiado para que la
max
operación considere "mejor" aquellos elementos que ocurrieron anteriormente en la lista original.Este código podría ser mucho más simple si se preocupara un poco menos por los problemas de grandes O en el tiempo y el espacio, por ejemplo ...:
misma idea básica, expresada de manera más simple y compacta ... pero, por desgracia, un espacio auxiliar O (N) adicional (para incorporar los iterables de los grupos a las listas) y el tiempo O (N al cuadrado) (para obtener el
L.index
de cada elemento) . Si bien la optimización prematura es la raíz de todo mal en la programación, elegir deliberadamente un enfoque O (N cuadrado) cuando hay un O (N log N) disponible, ¡va demasiado en contra de la escalabilidad! -)Finalmente, para aquellos que prefieren "oneliners" a la claridad y el rendimiento, una versión adicional de 1 línea con nombres adecuadamente destrozados :-).
fuente
groupby
requiere ordenar primero (O (NlogN)); usar unCounter()
conmost_common()
puede superar eso porque usa un heapq para encontrar el elemento de frecuencia más alta (para solo 1 elemento, ese es el tiempo O (N)). ComoCounter()
ahora está muy optimizado (el recuento se realiza en un bucle C), puede superar fácilmente esta solución incluso para listas pequeñas. Lo expulsa del agua para obtener grandes listas.Una línea más simple:
fuente
set(lst)
, toda la lista se debe comprobar de nuevo) ... Probablemente lo suficientemente rápido para la mayoría de usos, aunque ...set(lst)
conlst
y funcionará con elementos no hashables también; aunque más lentolist.count()
tiene que recorrer la lista en su totalidad , y lo hace para cada elemento único en la lista. Esto lo convierte en una solución O (NK) (O (N ^ 2) en el peor de los casos). ¡Usar unCounter()
solo toma tiempo O (N)!Tomando prestado de aquí , esto se puede usar con Python 2.7:
Funciona entre 4 y 6 veces más rápido que las soluciones de Alex, y es 50 veces más rápido que el one-liner propuesto por newacct.
Para recuperar el elemento que aparece primero en la lista en caso de empate:
fuente
most_common
está ordenado por conteo, no desordenado. Dicho esto, no elegirá el primer elemento en caso de empate; He agregado otra forma de usar el contador que elige el primer elemento.Lo que desea se conoce en estadísticas como modo, y Python, por supuesto, tiene una función incorporada para hacer exactamente eso por usted:
Tenga en cuenta que si no hay un "elemento más común", como los casos en que los dos primeros están empatados , esto aumentará
StatisticsError
, porque estadísticamente hablando, no hay modo en este caso.fuente
set
, y es plausibleO(n^3)
.Si no son intercambiables, puede ordenarlos y hacer un solo ciclo sobre el resultado contando los elementos (los elementos idénticos estarán uno al lado del otro). Pero podría ser más rápido hacerlos hashables y usar un dict.
fuente
Counter()
solución de AlexEsta es una solución O (n).
(se invierte para asegurarse de que devuelve el elemento de índice más bajo)
fuente
Sin el requisito sobre el índice más bajo, puede usar
collections.Counter
para esto:fuente
Ordene una copia de la lista y encuentre la ejecución más larga. Puede decorar la lista antes de ordenarla con el índice de cada elemento, y luego elegir la ejecución que comienza con el índice más bajo en el caso de un empate.
fuente
Una frase:
fuente
fuente
Solución simple de una línea
Devolverá el elemento más frecuente con su frecuencia.
fuente
Probablemente ya no necesites esto, pero esto es lo que hice para un problema similar. (Parece más largo de lo que es debido a los comentarios).
fuente
Basándose en la respuesta de Luiz , pero satisfaciendo la condición " en caso de sorteos, se debe devolver el elemento con el índice más bajo ":
Ejemplo:
fuente
Aquí:
Tengo la vaga sensación de que hay un método en algún lugar de la biblioteca estándar que le dará el recuento de cada elemento, pero no puedo encontrarlo.
fuente
Esta es la solución lenta obvia (O (n ^ 2)) si ni la clasificación ni el hashing son factibles, pero la comparación de igualdad (
==
) está disponible:Pero hacer que sus elementos se puedan compartir o ordenar (como lo recomiendan otras respuestas) casi siempre haría que encontrar el elemento más común sea más rápido si la longitud de su lista (n) es grande. O (n) en promedio con hashing, y O (n * log (n)) en el peor de los casos para la clasificación.
fuente
fuente
Necesitaba hacer esto en un programa reciente. Lo admito, no podía entender la respuesta de Alex, así que esto es con lo que terminé.
Lo comparé con la solución de Alex y es aproximadamente un 10-15% más rápido para listas cortas, pero una vez que superas los 100 elementos o más (probado hasta 200000) es aproximadamente un 20% más lento.
fuente
Hola, esta es una solución muy simple con O grande (n)
Donde numerar el elemento en la lista que se repite la mayor parte del tiempo
fuente
fuente
fuente
fuente