2009-06-06 18 views
167

Quiero crear un diccionario cuyos valores sean listas. Por ejemplo:Python creando un diccionario de listas

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

Si hago:

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

me siento 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 manera mejor de hacer esto? Digamos que no sé las claves que voy a necesitar hasta que esté en el segundo ciclo for. 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 entonces reemplazando

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, agregar "simplemente funcionaría". ¿Hay alguna forma de expresar que quiero un diccionario de listas vacías, incluso si no conozco todas las claves cuando primero creo la lista?

Respuesta

211

Puede utilizar defaultdict:

>>> from collections import defaultdict 
>>> d = defaultdict(list) 
>>> 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'])] 
+0

Otros diccionarios bajo el módulo 'collections' también funcionan de esta manera, por ejemplo' collections.OrderedDict'. – txsaw1

+1

Oh. Esto es genial. Y no tiene que inicializar a '= []'. ¡Buen material! –

21

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

El setdefault función en lugar de extraño nombre-dice "Obtener el valor de esta clave, o si dicha clave no está ahí, añadir este valor y luego devolverlo."

Editar: Como otros han señalado con acierto, defaultdict es una opción mejor y más moderna. setdefault sigue siendo útil en versiones anteriores de Python (anteriores a 2.5).

+2

Esto funciona, pero generalmente se prefiere usar el valor predeterminado cuando está disponible. –

+0

@David, sí, setdefault no fue el diseño más brillante, lo siento, casi nunca es la mejor opción. Creo que nosotros (los committers de Python) redimimos nuestra reputación colectiva con collections.defaultdict, aunque ;-). –

+0

@DavidZ, setdefault es diferente de defaultdict, ya que es más flexible: otherwhise, ¿cómo se especifican diferentes valores predeterminados para las diferentes claves del diccionario? –

37

Se puede construir con la lista de la comprensión de esta manera:

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

Su pregunta ya ha sido respondida, pero IIRC puede reemplazar li define como:

if d.has_key(scope_item): 

con:

if scope_item in d: 

Es decir, d referencias d.keys() en esa construcción. A veces defaultdict no es la mejor opción (por ejemplo, si desea ejecutar varias líneas de código después del else asociado con el if anterior), y la sintaxis in me resulta más fácil de leer.

Cuestiones relacionadas