Python creando un diccionario de listas

214

Quiero crear un diccionario cuyos valores son listas. Por ejemplo:

{
  1: ['1'],
  2: ['1','2'],
  3: ['2']
}

Si lo hago:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d[j].append(i)

Me sale un KeyError, porque d [...] no es una lista. En este caso, puedo agregar el siguiente código después de la asignación de a para inicializar el diccionario.

for x in range(1, 4):
    d[x] = list()

¿Hay una mejor manera de hacer esto? Digamos que no sé las claves que voy a necesitar hasta que esté en el segundo forciclo. Por ejemplo:

class relation:
    scope_list = list()
...
d = dict()
for relation in relation_list:
    for scope_item in relation.scope_list:
        d[scope_item].append(relation)

Una alternativa sería reemplazar

d[scope_item].append(relation)

con

if d.has_key(scope_item):
    d[scope_item].append(relation)
else:
    d[scope_item] = [relation,]

¿Cuál es la mejor manera de manejar esto? Idealmente, anexar "simplemente funcionaría". ¿Hay alguna forma de expresar que quiero un diccionario de listas vacías, incluso si no conozco todas las claves cuando creo la lista por primera vez?

usuario118662
fuente

Respuestas:

278

Puedes usar defaultdict :

>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> a = ['1', '2']
>>> for i in a:
...   for j in range(int(i), int(i) + 2):
...     d[j].append(i)
...
>>> d
defaultdict(<type 'list'>, {1: ['1'], 2: ['1', '2'], 3: ['2']})
>>> d.items()
[(1, ['1']), (2, ['1', '2']), (3, ['2'])]
carne_mecánica
fuente
1
Otros diccionarios en el collectionsmódulo también funcionan de esta manera, por ejemplo collections.OrderedDict.
txsaw1
2
Oh. Esto es genial. Y no tiene que inicializar a '= []'. ¡Buen material!
Wilmer E. Henao
1
NameError: name 'a' is not defined
S Andrew
51

Puedes construirlo con una lista de comprensión como esta:

>>> dict((i, range(int(i), int(i) + 2)) for i in ['1', '2'])
{'1': [1, 2], '2': [2, 3]}

Y para la segunda parte de su pregunta use defaultdict

>>> from collections import defaultdict
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
        d[k].append(v)

>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Nadia Alramli
fuente
32

Puedes usar setdefault:

d = dict()
a = ['1', '2']
for i in a:
    for j in range(int(i), int(i) + 2): 
        d.setdefault(j, []).append(i)

print d  # prints {1: ['1'], 2: ['1', '2'], 3: ['2']}

La setdefaultfunción de nombre extraño dice "Obtenga el valor con esta clave, o si esa clave no está allí, agregue este valor y luego devuélvalo".

Como otros han señalado correctamente, defaultdictes una opción mejor y más moderna. setdefaultsigue siendo útil en versiones anteriores de Python (anteriores a la 2.5).

RichieHindle
fuente
2
Esto funciona, pero generalmente se prefiere usar defaultdict cuando está disponible.
David Z
@David, sí, setdefault no fue el diseño más brillante, lo siento, casi nunca es la mejor opción. Sin embargo, creo que nosotros (los encargados de Python) redimimos nuestra reputación colectiva con collections.defaultdict ;-).
Alex Martelli
@DavidZ, setdefault es diferente de defaultdict, ya que es más flexible: de lo contrario, ¿cómo se especifican los diferentes valores predeterminados para diferentes claves de diccionario?
Alex Gidan
@AlexGidan Eso es cierto, pero no es particularmente relevante para esta pregunta.
David Z
Esta respuesta también es útil cuando necesita un OrderedDict y un valor predeterminado.
nimcap 01 de
2

Su pregunta ya ha sido respondida, pero IIRC puede reemplazar líneas como:

if d.has_key(scope_item):

con:

if scope_item in d:

Es decir, dreferencias d.keys()en esa construcción. A veces defaultdictno es la mejor opción (por ejemplo, si desea ejecutar varias líneas de código después de lo elseasociado con lo anterior if), y encuentro que la insintaxis es más fácil de leer.

spiffyman
fuente
2

Personalmente, solo uso JSON para convertir cosas en cadenas y viceversa. Cuerdas que entiendo.

import json
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
mydict = {}
hash = json.dumps(s)
mydict[hash] = "whatever"
print mydict
#{'[["yellow", 1], ["blue", 2], ["yellow", 3], ["blue", 4], ["red", 1]]': 'whatever'}
john ktejik
fuente
1

manera fácil es:

a = [1,2]
d = {}
for i in a:
  d[i]=[i, ]

print(d)
{'1': [1, ], '2':[2, ]}
Henning Lee
fuente