conversion de liste en Dictionnaire avec plusieurs valeurs par clé?

J'ai une liste Python qui contient des paires de clé / valeur:

l=[ [1, 'A'], [1, 'B'], [2, 'C'] ]

Je veux convertir la liste en un dictionnaire, où plusieurs valeurs par clé seraient agrégées en un tuple:

{ 1:('A', 'B'), 2:('C',) }

La solution itérative est triviale:

l=[ [1, 'A'], [1, 'B'], [2, 'C'] ]
d={}
for pair in l:
    if d.has_key(pair[0]):
        d[pair[0]]=d[pair[0]]+tuple(pair[1])
    else:
        d[pair[0]]=tuple(pair[1])

print d

{1: ('A', 'B'), 2: ('C',)}

Existe-t-il une solution pythonique plus élégante pour cette tâche?

46
demandé sur martineau 2011-03-21 16:28:47

4 réponses

from collections import defaultdict

d1 = defaultdict(list)

for k, v in l:
    d1[k].append(v)

d = dict((k, tuple(v)) for k, v in d1.iteritems())

d contient maintenant {1: ('A', 'B'), 2: ('C',)}

d1 est un defaultdict temporaire avec des listes comme valeurs, qui seront converties en tuples dans la dernière ligne. De cette façon, vous ajoutez des listes et ne recréez pas de tuples dans la boucle principale.

46
répondu eumiro 2011-03-21 13:30:14

Cette méthode est relativement efficace et assez compacte:

reduce(lambda x, (k,v): x[k].append(v) or x, l, defaultdict(list))

En Python3, cela devient (rendant les exportations explicites):

dict(functools.reduce(lambda x, d: x[d[0]].append(d[1]) or x, l, collections.defaultdict(list)))

Notez que reduce a été déplacé vers functools et que les lambdas n'acceptent plus les tuples. Cette version fonctionne toujours en 2.6 et 2.7.

10
répondu user2085084 2018-05-04 13:21:39

Utilisation de listes au lieu de tuples comme valeurs dict:

l=[ [1, 'A'], [1, 'B'], [2, 'C'] ]
d={}
for key, val in l:
    d.setdefault(key, []).append(val)

print d
7
répondu Sven Marnach 2011-03-21 13:30:31

Les clés sont-elles déjà triées dans la liste des entrées? Si c'est le cas, vous avez une solution fonctionnelle:

import itertools

lst = [(1, 'A'), (1, 'B'), (2, 'C')]
dct = dict((key, tuple(v for (k, v) in pairs)) 
           for (key, pairs) in itertools.groupby(lst, lambda pair: pair[0]))
print dct
# {1: ('A', 'B'), 2: ('C',)}
2
répondu tokland 2011-03-21 14:18:11