J'ai une liste Python qui contient des paires clé/valeur:
l=[ [1, 'A'], [1, 'B'], [2, 'C'] ]
Je veux convertir la liste en 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 Pythonic plus élégante pour cette tâche?
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 dict par défaut temporaire avec des listes en tant que 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.
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 la réduction a été déplacée vers functools et que les lambdas n'acceptent plus les tuples. Cette version fonctionne toujours en 2.6 et 2.7.
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
Les clés sont-elles déjà triées dans la liste de saisie? 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',)}