¿Hay alguna manera de tener un defaultdict(defaultdict(int))
para que el siguiente código funcione?
for x in stuff:
d[x.a][x.b] += x.c_int
d
necesita ser construido ad-hoc, dependiendo de x.a
y x.b
elementos.
Podría usar:
for x in stuff:
d[x.a,x.b] += x.c_int
pero entonces no podría usar:
d.keys()
d[x.a].keys()
python
collections
Jonathan
fuente
fuente
Respuestas:
Sí, así:
Se llamará al argumento de a
defaultdict
(en este casolambda: defaultdict(int)
) cuando intente acceder a una clave que no existe. El valor de retorno se establecerá como el nuevo valor de esta clave, lo que significa que en nuestro caso el valor ded[Key_doesnt_exist]
serádefaultdict(int)
.Si intenta acceder a una clave desde este último defaultdict, es decir
d[Key_doesnt_exist][Key_doesnt_exist]
, devolverá 0, que es el valor de retorno del argumento del último defaultdict, es decirint()
.fuente
defaultdict
(en este casolambda : defaultdict(int)
) cuando intente acceder a una clave que no existe y el valor de retorno se establecerá como el nuevo valor de esta clave que significa en nuestro casod[Key_dont_exist]
será el valor dedefaultdict(int)
, y si intenta acceder a una clave desde este último defaultdict, es decird[Key_dont_exist][Key_dont_exist]
, devolverá 0, que es el valor de retorno del argumento del último ,defaultdict
es decirint()
, espero que esto haya sido útil.defaultdict
debería ser una función.defaultdict(int)
es un diccionario, mientras quelambda: defaultdict(int)
es una función que devuelve un diccionario.defaultdict(lambda: defaultdict(lambda: defaultdict(int)))
El parámetro para el constructor defaultdict es la función que se llamará para construir nuevos elementos. ¡Entonces usemos una lambda!
Desde Python 2.7, hay una solución aún mejor con Counter :
Algunas características adicionales
Para obtener más información, consulte PyMOTW - Colecciones - Tipos de datos de contenedor y Documentación de Python - colecciones
fuente
d = defaultdict(lambda : Counter())
lugar ded = defaultdict(lambda : defaultdict(int))
abordar específicamente el problema como se planteó originalmente.d = defaultdict(Counter())
no puede usar una lambda en este casoCounter
objeto. Es decir:d = defaultdict(Counter)
Me parece un poco más elegante de usar
partial
:Por supuesto, esto es lo mismo que una lambda.
fuente
Como referencia, es posible implementar un
defaultdict
método de fábrica anidado genérico a través de:La profundidad define el número de diccionarios anidados antes de
default_factory
usar el tipo definido en . Por ejemplo:fuente
ndd = nested_defaultdict(dict) .... ndd['a']['b']['c']['d'] = 'e'
tirosKeyError: 'b'
depth=0
, que no siempre se desea si la profundidad es desconocida al momento de la llamada. Fácilmente reparable agregando una líneaif not depth: return default_factory()
, en la parte superior de la función, aunque probablemente haya una solución más elegante.Las respuestas anteriores han abordado cómo hacer dos niveles o n niveles
defaultdict
. En algunos casos, quieres uno infinito:Uso:
fuente
Otros han respondido correctamente su pregunta sobre cómo hacer que funcione lo siguiente:
Una alternativa sería usar tuplas para claves:
Lo bueno de este enfoque es que es simple y se puede ampliar fácilmente. Si necesita un mapeo de tres niveles de profundidad, simplemente use una tupla de tres elementos para la clave.
fuente