En su pregunta, usted pidió la forma más rápida de hacerlo. Como se ha demostrado repetidamente, particularmente con Python, la intuición no es una guía confiable: es necesario medir.
Aquí está una prueba simple de varias implementaciones diferentes:
import sys
from collections import Counter, defaultdict
from itertools import groupby
from operator import itemgetter
from timeit import timeit
L = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]
def max_occurrences_1a(seq=L):
"dict iteritems"
c = dict()
for item in seq:
c[item] = c.get(item, 0) + 1
return max(c.iteritems(), key=itemgetter(1))
def max_occurrences_1b(seq=L):
"dict items"
c = dict()
for item in seq:
c[item] = c.get(item, 0) + 1
return max(c.items(), key=itemgetter(1))
def max_occurrences_2(seq=L):
"defaultdict iteritems"
c = defaultdict(int)
for item in seq:
c[item] += 1
return max(c.iteritems(), key=itemgetter(1))
def max_occurrences_3a(seq=L):
"sort groupby generator expression"
return max(((k, sum(1 for i in g)) for k, g in groupby(sorted(seq))), key=itemgetter(1))
def max_occurrences_3b(seq=L):
"sort groupby list comprehension"
return max([(k, sum(1 for i in g)) for k, g in groupby(sorted(seq))], key=itemgetter(1))
def max_occurrences_4(seq=L):
"counter"
return Counter(L).most_common(1)[0]
versions = [max_occurrences_1a, max_occurrences_1b, max_occurrences_2, max_occurrences_3a, max_occurrences_3b, max_occurrences_4]
print sys.version, "\n"
for vers in versions:
print vers.__doc__, vers(), timeit(vers, number=20000)
Los resultados en mi máquina:
2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)]
dict iteritems (4, 6) 0.202214956284
dict items (4, 6) 0.208412885666
defaultdict iteritems (4, 6) 0.221301078796
sort groupby generator expression (4, 6) 0.383440971375
sort groupby list comprehension (4, 6) 0.402786016464
counter (4, 6) 0.564319133759
lo que parece que la solución Counter
no es el más rápido. Y, en este caso al menos, groupby
es más rápido. defaultdict
es bueno pero pagas un poco por su conveniencia; es un poco más rápido usar un dict
normal con un get
.
¿Qué sucede si la lista es mucho más grande? La adición de L *= 10000
a la prueba anterior y reducir el número de repeticiones a 200:
dict iteritems (4, 60000) 10.3451900482
dict items (4, 60000) 10.2988479137
defaultdict iteritems (4, 60000) 5.52838587761
sort groupby generator expression (4, 60000) 11.9538850784
sort groupby list comprehension (4, 60000) 12.1327362061
counter (4, 60000) 14.7495789528
Ahora defaultdict
es el claro ganador. Entonces, tal vez el costo del método 'obtener' y la pérdida del complemento en el lugar se suma (un examen del código generado se deja como un ejercicio).
Pero con los datos de prueba modificados, el número de valores de elementos únicos no cambió, por lo que presumiblemente dict
y defaultdict
tienen una ventaja sobre las otras implementaciones. Entonces, ¿qué sucede si utilizamos la lista más grande pero aumentamos sustancialmente la cantidad de artículos únicos? Sustitución de la inicialización de L con:
LL = [1,2,45,55,5,4,4,4,4,4,4,5456,56,6,7,67]
L = []
for i in xrange(1,10001):
L.extend(l * i for l in LL)
dict iteritems (2520, 13) 17.9935798645
dict items (2520, 13) 21.8974409103
defaultdict iteritems (2520, 13) 16.8289561272
sort groupby generator expression (2520, 13) 33.853593111
sort groupby list comprehension (2520, 13) 36.1303369999
counter (2520, 13) 22.626899004
Así que ahora Counter
es claramente más rápido que las soluciones groupby
pero aún más lento que las versiones de iteritems
dict
y defaultdict
.
El objetivo de estos ejemplos no es producir una solución óptima. El punto es que a menudo no es uno solución general óptima. Además, hay otros criterios de rendimiento.Los requisitos de memoria variarán sustancialmente entre las soluciones y, a medida que aumenta el tamaño de la entrada, los requisitos de memoria pueden convertirse en el factor primordial en la selección del algoritmo.
En pocas palabras: todo depende y usted necesita medir.
Usted dice que son capaces de resolverlo También sería educativo para los demás si pudiera proporcionar su propia solución como punto de partida. –