Ha preguntado cuál era más eficiente. Suponiendo que está hablando de la velocidad de ejecución: si sus datos son pequeños, no importa. Si es grande y típico, el caso "ya existe" ocurrirá mucho más a menudo que el caso "no está en dict". Esta observación explica algunos de los resultados.
A continuación se muestra un código que se puede utilizar con el módulo timeit
para explorar la velocidad sin sobrecarga de lectura de archivos. Me he tomado la libertad de agregar un quinto método, que no es sencillo y se ejecutará en cualquier Python desde al menos 1.5.2 [probado] en adelante.
from collections import defaultdict, Counter
def tally0(iterable):
# DOESN'T WORK -- common base case for timing
d = {}
for item in iterable:
d[item] = 1
return d
def tally1(iterable):
d = {}
for item in iterable:
if item in d:
d[item] += 1
else:
d[item] = 1
return d
def tally2(iterable):
d = {}
for item in iterable:
try:
d[item] += 1
except KeyError:
d[item] = 1
return d
def tally3(iterable):
d = defaultdict(int)
for item in iterable:
d[item] += 1
def tally4(iterable):
d = Counter()
for item in iterable:
d[item] += 1
def tally5(iterable):
d = {}
dg = d.get
for item in iterable:
d[item] = dg(item, 0) + 1
return d
ejecución típica (en "Símbolo del sistema" Windows XP ventana):
prompt>\python27\python -mtimeit -s"t=1000*'now is the winter of our discontent made glorious summer by this son of york';import tally_bench as tb" "tb.tally1(t)"
10 loops, best of 3: 29.5 msec per loop
Estos son los resultados (ms por circular):
0 base case 13.6
1 if k in d 29.5
2 try/except 26.1
3 defaultdict 23.4
4 Counter 79.4
5 d.get(k, 0) 29.2
Otro ensayo de tiempo:
prompt>\python27\python -mtimeit -s"from collections import defaultdict;d=defaultdict(int)" "d[1]+=1"
1000000 loops, best of 3: 0.309 usec per loop
prompt>\python27\python -mtimeit -s"from collections import Counter;d=Counter()" "d[1]+=1"
1000000 loops, best of 3: 1.02 usec per loop
La velocidad de Counter
posiblemente se deba a que se implementa parcialmente en código Python, mientras que defaultdict
está completamente en C (en 2.7, como mínimo).
Tenga en cuenta que no es sólo Counter()
"azúcar sintáctico" para defaultdict(int)
- implementa un completo bag
aka multiset
objeto - véase la documentación para más detalles; pueden evitar que reinventes la rueda si necesitas un postprocesamiento sofisticado. Si todo lo que quiere hacer es contar cosas, use defaultdict
.
actualización en respuesta a una pregunta de @Steven Rumbalski: """ Tengo curiosidad, ¿qué ocurre si se mueve la iterable en el constructor del contador:? D = Contador (iterable) (tengo Python 2.6 y no puede probarlo) """
tally6:. simplemente no d = Count(iterable); return d
, toma 60,0 milisegundos
se podría buscar en la fuente (collections.py en el repositorio SVN) ... aquí es lo que mi Python27\Lib\collections.py
hace cuando iterable
no es una instancia de asignación:
self_get = self.get
for elem in iterable:
self[elem] = self_get(elem, 0) + 1
¿Has visto ese código en algún lugar antes? Hay un montón de equipaje de mano solo para llamar al código ejecutable en Python 1.5.2 :-O
Edición adicional: estoy ejecutando la versión 2.7. Debería haber agregado esto antes! –
'Counter' ** es más lento ** pero tiene mucha más funcionalidad que' defaultdict (int) '- ver mi respuesta. –
¿puede incrementar valores múltiples? – Mohsin