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?

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'])]

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])]

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).


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.


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'}

1

manera fácil es:

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

print(d)
{'1': [1, ], '2':[2, ]}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.