¿Python dice cómo crear una clave o agregar un elemento a la clave?

161

Tengo un diccionario vacio Nombre: dict_x es tener claves cuyos valores son listas.

De una iteración separada, obtengo una clave (ej .:) key_123y un elemento (una tupla) para colocar en la lista del dict_xvalor de key_123.

Si esta clave ya existe, quiero agregar este elemento. Si esta clave no existe, quiero crearla con una lista vacía y luego agregarla o simplemente crearla con una tupla.

En el futuro, cuando vuelva a aparecer esta clave, ya que existe, quiero que el valor se agregue nuevamente.

Mi código consiste en esto:

Obtenga clave y valor.

Vea si la clave NO existe en dict_x.

y si no lo creas: dict_x[key] == []

Después: dict_x[key].append(value)

¿Es esta la manera de hacerlo? ¿Debo tratar de usar try/exceptbloques?

Phil
fuente

Respuestas:

254

Uso dict.setdefault():

dic.setdefault(key,[]).append(value)

ayuda (dict.setdefault) :

    setdefault(...)
        D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D
Ashwini Chaudhary
fuente
44
Solía ​​hacer esto dict_x[key] = [some_value] if not dict_x.has_key(key) else dict_x[key] + [some_value]pero esta respuesta sugiere una forma mucho mejor. De hecho, se pone set()como argumento y le permite utilizar el add()método ...
fatih_dur
66

Estas son las diversas formas de hacer esto para que pueda comparar cómo se ve y elegir lo que le gusta. Los ordené de una manera que creo que es más "pitónica" , y comenté los pros y los contras que podrían no ser obvios a primera vista:

Utilizando collections.defaultdict:

import collections
dict_x = collections.defaultdict(list)

...

dict_x[key].append(value)

Pros: Probablemente el mejor rendimiento. Contras: No disponible en Python 2.4.x.

Utilizando dict().setdefault():

dict_x = {}

...

dict_x.setdefault(key, []).append(value)

Contras: Creación ineficiente de list()s no utilizados .

Utilizando try ... except:

dict_x = {}

...

try:
    values = dict_x[key]
except KeyError:
    values = dict_x[key] = []
values.append(value)

O:

try:
    dict_x[key].append(value)
except KeyError:
    dict_x[key] = [value]
antak
fuente
Hola, ¿por qué crees que .setdefault crea diccionarios innecesarios?
Phil
2
No creo que .setdefault()crea diccionarios innecesarios. Creo que estoy creando lists innecesarios []en el segundo argumento de .setdefault()que nunca se usa si keyya existe. Podría usar dict.setdefault()(en beneficio del hashing de claves eficiente), y usar una variable para reutilizar lists no utilizados , pero eso agrega algunas líneas más de código.
antak
1
IIRC, en Python, una lista vacía en igualdad se considera una constante en el nivel de bytecode, pero esto necesita alguna confirmación por parte de un gurú de bytecode (o simplemente use el módulo de desastre).
gaborous
El uso .setdefaultcrea una búsqueda de clave donde la ausencia de dictresultados dará como resultado un KeyErrortiempo collections.defaultdict(list)crea una dictbúsqueda de clave donde la ausencia insertará un list
espacio
Intenté algo similar a collections.defaultdict en mi propio código y tuvo efectos secundarios inesperados. Por ejemplo, considere el siguiente intercambio IDLE: >>> list_dict = defaultdict (list) >>> len (list_dict) 0 >>> len (list_dict [0]) 0 >>> len (list_dict) 1 Parece que cuando Python invoca el valor predeterminado agrega la clave al diccionario sin que usted lo configure activamente, lo que creará muchas listas vacías si el valor predeterminado se usa mucho. Voy a rodar mis propias funciones de contenedor para el diccionario, ineficientes pero con suerte más predecibles.
RDBury
26

Puedes usar un defaultdict para esto.

from collections import defaultdict
d = defaultdict(list)
d['key'].append('mykey')

Esto es un poco más eficiente que setdefaultporque no terminas creando nuevas listas que no terminas usando. Cada llamada a setdefaultva a crear una nueva lista, incluso si el elemento ya existe en el diccionario.

Nathan Villaescusa
fuente
14

Puedes usar defaultdict en collections.

Un ejemplo de doc:

s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
    d[k].append(v)
iMom0
fuente
0
dictionary['key'] = dictionary.get('key', []) + list_to_append
Tomas Silva Ebensperger
fuente
1
Debe explicar la ventaja (muy menor) que esto tiene en presencia de ciertas excepciones; como solo código, no está claro por qué se necesita la respuesta adicional.
Davis Herring
Hola, solo una alternativa sin importaciones adicionales. Esto se puede hacer claramente con una declaración if. Solo estoy sugiriendo una alternativa usando el poder de .get () en lugar de usar dict [].
Tomas Silva Ebensperger
Las dos respuestas principales mencionan dos formas diferentes sin importación (aunque no dict.get).
Davis Herring