转置(旋转)python 中的列表字典

Transposing (pivoting) a dict of lists in python

我的字典如下所示:

{'x': [1, 2, 3], 'y': [4, 5, 6]}

我想将其转换为以下格式:

[{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, {'x': 3, 'y': 6}] 

我可以通过显式循环来完成,但是有没有好的 pythonic 方法来完成它?

编辑:原来有一个类似的问题 here and one of the answers 与此处接受的答案相同,但该答案的作者写道 "I do not condone the use of such code in any kind of real system"。有人可以解释为什么这样的代码不好吗?在我看来很优雅。

使用 zip() 几次,指望 dict.items() 和直接迭代 dict return 元素的顺序相同,只要字典在两者之间没有突变:

[dict(zip(d, col)) for col in zip(*d.values())]

zip(*d.values()) 调用 transposes the list valueszip(d, col) 调用再次将每列与字典中的键配对。

以上相当于手动拼出按键:

[dict(zip(('x', 'y'), col)) for col in zip(d['x'], d['y'])]

无需手动拼出按键。

演示:

>>> d = {'x': [1, 2, 3], 'y': [4, 5, 6]}
>>> [dict(zip(d, col)) for col in zip(*d.values())]
[{'x': 1, 'y': 4}, {'x': 2, 'y': 5}, {'x': 3, 'y': 6}]

我不认为有任何容易阅读,简洁的 1 行(虽然可能不难想出一个 困难 阅读,简洁的 1-liner ... ;) -- 至少在一般情况下不是(任意数量的字典项,其中键是未知的)。

如果您知道 字典的键,我认为使用它可能是最简单的(特别是因为示例中只有两个键)。

在 2 遍中构建新的字典。第一遍填写x,第二遍填写y.

new_dicts = [{'x': x} for x in d['x']]
for new_dict, y in zip(new_dicts, d['y']):
    new_dict['y'] = y

如果你宁愿一次完成,我认为这也不错:

new_dicts = [{'x': x, 'y': y} for x, y in zip(d['x'], d['y'])]

如果你有一个键列表,我可能会略有不同...

import operator
value_getter = operator.itemgetter(*list_of_keys)
new_dicts_values = zip(*value_getter(d))
new_dicts = [
    dict(zip(list_of_keys, new_dict_values))
    for new_dict_values in new_dicts_values]

这与 Martijn 的回答中采用的策略几乎相同……但是,我认为稍微分解一下并给事物命名有助于让事情变得更清楚一些。此外,这消除了必须说服自己将无序列表 dict 与列值的无序列表压缩是可以的心理开销,因为它们以相同的方式无序列表...

当然,如果您实际上没有密钥列表,您总是可以通过

获得一个
list_of_keys = list(d)

如果

d = {'x': [1, 2, 3], 'y': [4, 5, 6]}

可以试试:

keys = d.keys()

print map(lambda tupl: map(lambda k,v: {k:v}, keys, tupl), zip(*d.itervalues()))

看起来 pythonic 但对于较大的条目,每次 map 调用 lambda 函数时 lambda 调用的开销都会增加。