多值单词列表中的单个词组

时间:2016-05-04 03:24:22

标签: python django algorithm django-forms

拥有以下 dict 结构

>>> 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']
}

获取以下列表单个词汇的有效方法是什么?

>>> 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}
]

到目前为止,我试过了:

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

后不久

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()))

假设Python 2.7.x在性能方面有什么更好的方法?

>>> 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。对于那些好奇的,初始dict是一个Django MultiValue QueryDict,包含许多具有相同名称的<input>值。

2 个答案:

答案 0 :(得分:4)

使用itertools.zip_longest和列表理解:

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

示例:

>>> 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 :(得分:0)

没有硬编码值: 时间: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))