¿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
dnecesita ser construido ad-hoc, dependiendo de x.ay x.belementos.
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 ,defaultdictes decirint(), espero que esto haya sido útil.defaultdictdeberí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 casoCounterobjeto. 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
defaultdictmétodo de fábrica anidado genérico a través de:La profundidad define el número de diccionarios anidados antes de
default_factoryusar 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