2016-05-04 11 views
2

Mit folgenden dict StrukturMehrwertige dict zur Liste der einzelnen dicts

>>> d = { 
    'email': ['e_val1', 'e_val2', 'e_val3', 'e_val4', 'e_val5'], 
    'id' : ['i_val1', 'i_val2', 'i_val3', 'i_val4'], 
    'ref' : ['r_val1', 'r_val2', 'r_val3', 'r_val4'] 
} 

was wäre ein effektiver Weg, um die folgende Liste einzelner dicts zu bekommen?

>>> l = [ 
    {'email': 'e_val1', 'id': 'i_val1', 'ref': 'r_val1'}, 
    {'email': 'e_val2', 'id': 'i_val2', 'ref': 'r_val2'}, 
    {'email': 'e_val3', 'id': 'i_val3', 'ref': 'r_val3'}, 
    {'email': 'e_val4', 'id': 'i_val4', 'ref': 'r_val4'}, 
    {'email': 'e_val5', 'id': None, 'ref': None} 
] 

Bisher habe ich versucht:

def split(d): 
    l, longest = [], False 
    for k, v in d.items(): 
     longest = max(longest, len(v)) 

    for pointer in range(longest): 
     r = {} 
     for k, v in d.items(): 
      try: 
       r[k] = v[pointer] 
      except IndexError: 
       # current list is shorter than longest 
       r[k] = None 
     l.append(r) 
    return l 

die kurz nach

wurde
from itertools import izip_longest 

def split(d): 
    """ 
    With Python < 2.7, 
     - itertools.izip_longest(*d.values())    
    might be substituted by map with None: 
     - map(None, *d.values())     
    """ 
    _zipper = lambda keys: lambda v: dict(zip(keys, v)) 
    lmb = _zipper(d.keys()) 
    return map(lmb, 
       itertools.izip_longest(*d.values())) 

Unter der Annahme, Python 2.7.x, in Bezug auf Leistung, was eine bessere Möglichkeit wäre?

>>> from timeit import timeit 

>>> # with map 
>>> timeit(setup=""" 
... d={'email': ['e_val1', 'e_val2', 'e_val3', 'e_val4', 'e_val5'], 
... 'id': ['i_val1', 'i_val2', 'i_val3', 'i_val4'], 
... 'ref': ['r_val1', 'r_val2', 'r_val3', 'i_val4']}; 
... _zipper=lambda keys: lambda v: dict(zip(keys, v))""", 
... stmt=""" 
... lmb=_zipper(d.keys()); 
... map(lmb, map(None, *d.values()))""") 
16.14903998374939 

>>> # with itertools.izip_longest 
>>> timeit(setup=""" 
... d={'email': ['e_val1', 'e_val2', 'e_val3', 'e_val4', 'e_val5'], 
... 'id': ['i_val1', 'i_val2', 'i_val3', 'i_val4'], 
... 'ref': ['r_val1', 'r_val2', 'r_val3', 'i_val4']}; 
... _zipper=lambda keys: lambda v: dict(zip(keys, v))""", 
... stmt=""" 
... lmb=_zipper(d.keys()); 
... map(lmb, izip_longest(*d.values()))""") 
18.98265790939331 

P.S. Für die Neugierigen ist das erste dict ein Django MultiValue QueryDict, das viele <input> Werte mit denselben Namen enthält.

Antwort

4

Mit itertools.zip_longest und Liste Verständnis:

[{'email': i, 'id': j, 'ref': k} for (i, j, k) in itertools.zip_longest(d.get('email'), d.get('id'), d.get('ref'))] 

Beispiel:

>>> d 
{'ref': ['r_val1', 'r_val2', 'r_val3', 'r_val4'], 'id': ['i_val1', 'i_val2', 'i_val3', 'i_val4'], 'email': ['e_val1', 'e_val2', 'e_val3', 'e_val4', 'e_val5']} 

>>> [{'email': i, 'id': j, 'ref': k} for (i, j, k) in itertools.zip_longest(d.get('email'), d.get('id'), d.get('ref'))] 
[{'ref': 'r_val1', 'id': 'i_val1', 'email': 'e_val1'}, {'ref': 'r_val2', 'id': 'i_val2', 'email': 'e_val2'}, {'ref': 'r_val3', 'id': 'i_val3', 'email': 'e_val3'}, {'ref': 'r_val4', 'id': 'i_val4', 'email': 'e_val4'}, {'ref': None, 'id': None, 'email': 'e_val5'}] 
+1

1. aufgrund Hardcoding Werte, gemessen 3,67 Sekunden oder 6x schneller. Natürlich wird Hardcoding keine Zyklen verschwenden. 2. python 2.7 nein zip_longest aber izip_longest. Ich kann nicht sehen, wie das wiederverwendet werden könnte. –

0

keine fest codierten Werte: timeit: 5,15033793449

def form_dict(key_index): 
    each_dict = {} 
    for k in d.keys(): 
     if key_index < len(d[k]): 
      each_dict[k] = d[k][key_index] 
     else: 
      each_dict[k] = None 
    return each_dict 

def get_converted_list(): 
    Max = max([len(v) for v in d.values()]) 
    return map(form_dict, range(0, Max)) 
+0

Bitte messen Sie mit Zeit. Danke für das Maximum für die gesamte Sequenz und nicht für den Wert. –

Verwandte Themen