结合列表和字典推导式
我有一些比较复杂的逻辑,想用更简洁的方式来处理。
简单来说,我有一个字典对象,里面有16个我关心的值。我用下面的方式来获取我想要的键:
["I%d" % (i,) for i in range(16)]
这个源字典大致长这样:
{ "I0": [0,1,5,2], "I1": [1,3,5,2], "I2": [5,9,10,1], ... }
我想把这个字典转换成类似这样的结构:
[
{ "I0": 0, "I1": 1, "I2": 5, ... }
{ "I0": 1, "I1": 3, "I2": 9, ... }
...
]
我该如何使用列表和字典的简洁写法,把我的源字典转换成目标的字典列表呢?
3 个回答
0
这里有一个简单快捷的解决办法:
keys = data.keys()
values = data.values()
transformed = [dict(zip(keys, t)) for t in zip(*values)]
关键在于对值的矩阵进行转置,这个操作是通过 zip(*values)
来完成的,然后我们只需要重新构建字典。
6
我会这样解决这个问题:
首先,我会为每个键创建一个包含元组的列表,其中第一个项目是键,第二个项目是列表中的一个值:
>>> [ [ (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)]]
然后,我会遍历这个列表,使用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))]
这些子列表可以作为参数传递给字典构造器:
>>> [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}]
不过,实际上,我并不推荐大家只用一行代码来完成这样的事情:
>>> 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}]
其实,我发布这个回答主要是想建议你把解决方案分成多行来写。
8
这是一个可以在任意大小上应用的完全可行的解决方案。
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())))
具体来说:(我正在使用 ipython
,下划线 _
代表之前的输出)
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}]