Python créant un dictionnaire de listes


214

Je veux créer un dictionnaire dont les valeurs sont des listes. Par exemple:

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

Si je fais:

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

J'obtiens une KeyError, car d [...] n'est pas une liste. Dans ce cas, je peux ajouter le code suivant après l'attribution d'un pour initialiser le dictionnaire.

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

Y a-t-il une meilleure manière de faire cela? Disons que je ne connais pas les clés dont je vais avoir besoin jusqu'à ce que je sois dans la deuxième forboucle. Par exemple:

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

Une alternative serait alors de remplacer

d[scope_item].append(relation)

avec

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

Quelle est la meilleure façon de gérer cela? Idéalement, l'ajout «fonctionnerait tout simplement». Existe-t-il un moyen d'exprimer que je veux un dictionnaire de listes vides, même si je ne connais pas toutes les clés lorsque je crée la liste pour la première fois?

Réponses:


279

Vous pouvez utiliser 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
D'autres dictionnaires sous le collectionsmodule fonctionnent également de cette façon, par exemple collections.OrderedDict.
txsaw1

2
Oh. C'est bien. Et vous n'avez pas à initialiser à '= []'. Bon produit!
Wilmer E. Henao

1
NameError: name 'a' is not defined
S Andrew

52

Vous pouvez le construire avec une compréhension de liste comme ceci:

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

Et pour la deuxième partie de votre question, utilisez 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

Vous pouvez utiliser 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']}

Le plutôt bizarrement nommé setdefault fonction au dit "Obtenez la valeur avec cette clé, ou si cette clé n'est pas là, ajoutez cette valeur puis retournez-la."

Comme d'autres l'ont souligné à juste titre, defaultdictc'est un choix meilleur et plus moderne. setdefaultest toujours utile dans les anciennes versions de Python (antérieures à 2.5).


2
Cela fonctionne, mais il est généralement préférable d'utiliser defaultdict lorsqu'il est disponible.
David Z

@ David, oui, setdefault n'était pas le design le plus brillant, désolé - ce n'est presque jamais le meilleur choix. Je pense que nous (les committers Python) avons racheté notre réputation collective avec collections.defaultdict ;-).
Alex Martelli

@DavidZ, setdefault est différent de defaultdict, car il est plus flexible: sinon, comment spécifiez-vous différentes valeurs par défaut pour différentes clés de dictionnaire?
Alex Gidan

@AlexGidan C'est vrai, mais pas particulièrement pertinent pour cette question.
David Z

Cette réponse est également utile lorsque vous avez besoin d'un OrderedDict et d'une valeur par défaut.
nimcap

2

Votre question a déjà reçu une réponse, mais IIRC vous pouvez remplacer des lignes comme:

if d.has_key(scope_item):

avec:

if scope_item in d:

Autrement dit, des dréférences d.keys()dans cette construction. Parfois, ce defaultdictn'est pas la meilleure option (par exemple, si vous souhaitez exécuter plusieurs lignes de code après celles elseassociées à ce qui précède if), et je trouve la insyntaxe plus facile à lire.


2

Personnellement, j'utilise simplement JSON pour convertir des choses en chaînes et inversement. Des cordes je comprends.

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

le moyen le plus simple est:

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

print(d)
{'1': [1, ], '2':[2, ]}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.