2012-01-19 18 views
6

Ho una specie di logica prolissa che mi piacerebbe compattare con alcune comprensioni.Lista combinata e comprensione del ditt.

In sostanza, ho un oggetto dict che sto leggendo da cui ho 16 valori in cui sono interessato. Sto ricevendo le chiavi che voglio con la seguente comprensione:

["I%d" % (i,) for i in range(16)] 

Il dizionario fonte tipo di assomiglia a questo:

{ "I0": [0,1,5,2], "I1": [1,3,5,2], "I2": [5,9,10,1], ... } 

vorrei mappare essenzialmente questo dizionario di essere qualcosa di simile questo:

[ 
    { "I0": 0, "I1": 1, "I2": 5, ... } 
    { "I0": 1, "I1": 3, "I2": 9, ... } 
    ... 
] 

Come posso mappare le cose con lista e comprensioni del dizionario per trasformare la mia fonte dict nella mia lista di destinazione dei dizionari?

risposta

7

Questa è una soluzione completamente funzionale che può essere applicata su dimensioni arbitrarie.

d = { "I0": [0,1,5,2], "I1": [1,3,5,2], "I2": [5,9,10,1]} 
map(dict, zip(*map(lambda (k, v): map(lambda vv: (k, vv), v), d.iteritems()))) 

a elaborate: (I'm using ipython e l'underscore _ means l'output precedente)

In [1]: d = {'I0': [0, 1, 5, 2], 'I1': [1, 3, 5, 2], 'I2': [5, 9, 10, 1]} 

In [2]: map(lambda (k, v): map(lambda vv: (k, vv), v), _.iteritems()) 
Out[2]: 
[[('I1', 1), ('I1', 3), ('I1', 5), ('I1', 2)], 
[('I0', 0), ('I0', 1), ('I0', 5), ('I0', 2)], 
[('I2', 5), ('I2', 9), ('I2', 10), ('I2', 1)]] 

In [3]: zip(*_) 
Out[3]: 
[(('I1', 1), ('I0', 0), ('I2', 5)), 
(('I1', 3), ('I0', 1), ('I2', 9)), 
(('I1', 5), ('I0', 5), ('I2', 10)), 
(('I1', 2), ('I0', 2), ('I2', 1))] 

In [4]: map(dict, _) 
Out[4]: 
[{'I0': 0, 'I1': 1, 'I2': 5}, 
{'I0': 1, 'I1': 3, 'I2': 9}, 
{'I0': 5, 'I1': 5, 'I2': 10}, 
{'I0': 2, 'I1': 2, 'I2': 1}] 
6

Come would solve it:

Firstly, ho would get per ogni key un elenco contenente tuple, dove il primo elemento sarebbe la chiave e il secondo sarebbe uno dei valori dall'elenco:

>>> [ [ (k, i) for i in l] for k, l in d.items() ] 
[[('I1', 1), ('I1', 3), ('I1', 5), ('I1', 2)], 
    [('I0', 0), ('I0', 1), ('I0', 5), ('I0', 2)], 
    [('I2', 5), ('I2', 9), ('I2', 10), ('I2', 1)]] 

Poi sarebbe trasversali questo elenco, creando una lista di tuple contenenti ogni tasto corrispondente, utilizzando la funzione zip:

>>> list(zip(*[ [ (k, i) for i in l] for k, l in d.items() ])) 
[(('I1', 1), ('I0', 0), ('I2', 5)), 
(('I1', 3), ('I0', 1), ('I2', 9)), 
(('I1', 5), ('I0', 5), ('I2', 10)), 
    (('I1', 2), ('I0', 2), ('I2', 1))] 

Questi elenchi secondari possono passato come parametro al costruttore dict:

>>> [dict(lp) for lp in zip(*[ [ (k, i) for i in l] for k, l in d.items() ])] 
[{'I0': 0, 'I1': 1, 'I2': 5}, 
{'I0': 1, 'I1': 3, 'I2': 9}, 
{'I0': 5, 'I1': 5, 'I2': 10}, 
{'I0': 2, 'I1': 2, 'I2': 1}] 

in pratica, tuttavia, non avrei mai raccomandare uno per fare una cosa del genere in una sola riga:

>>> pairs = [ [ (k, i) for i in l] for k, l in d.items() ] 
>>> transversed = zip(*pairs) 
>>> ds = [dict(t) for t in transversed] 
>>> pprint(ds) 
[{'I0': 0, 'I1': 1, 'I2': 5}, 
{'I0': 1, 'I1': 3, 'I2': 9}, 
{'I0': 5, 'I1': 5, 'I2': 10}, 
{'I0': 2, 'I1': 2, 'I2': 1}] 

in realtà, io wo direi che ho postato questa risposta per lo più per suggerirti di dividere la tua soluzione in più di una riga.

+0

+1 per l'elaborazione passo passo. I nostri approcci sono gli stessi eccetto che ho fatto largo uso di 'map' :) – qiao

+0

@qiao sì, abbiamo adottato lo stesso approccio in un modo più astratto. Ho solo qualche preferenza per la comprensione delle liste, ma la tua soluzione è eccellente. – brandizzi

0

C'è soluzione a breve e semplice:

keys = data.keys() 
values = data.values() 
transformed = [dict(zip(keys, t)) for t in zip(*values)] 

La chiave qui recepisce o matrice di valori, che viene fatto con zip(*values), poi abbiamo appena ricostruire dicts.

Problemi correlati