将基于共同键值的多个字典合并为一个字典

4

基本上,我有一个有序字典列表;

lst = [
    OrderedDict([('type', 'character'), ('letter', 'a')]),
    OrderedDict([('type', 'character'), ('letter', 'b')]),
    OrderedDict([('type', 'character'), ('letter', 'c')]),
    OrderedDict([('type', 'character'), ('letter', 'd')]),
    OrderedDict([('type', 'integer'), ('number', '1')]),
    OrderedDict([('type', 'integer'), ('number', '2')]),
    OrderedDict([('type', 'integer'), ('number', '3')]),
    OrderedDict([('type', 'integer'), ('number', '4')])
]

我希望你能将其改为

lst = [
    OrderedDict([('type', 'character'), ('letter', ['a', 'b', 'c', 'd'])]),
    OrderedDict([('type', 'integer'), ('number', ['1', '2', '3', '4'])])
]

我考虑创建一个类型值列表 ['character', 'integer'],然后遍历所有字典,尝试将字母/数字分组到一个列表中,然后创建一个新的字典列表来填充我得到的数据。不确定这是否是最佳方法。感谢您的帮助。
3个回答

2

如果您的字典列表已经排序,则可以直接使用itertools.groupby。在字典中将项目与其相关字符串之间进行映射有助于避免多次调用d.items,并使代码可扩展到新类型:

from collections import OrderedDict
from itertools import groupby

_map = {'character': 'letter', 'integer': 'number'}

l = [OrderedDict([('type', k), (_map[k], [d[_map[k]] for d in g])]) for k, g in groupby(lst, lambda x: x['type'])]
print(l)
# [OrderedDict([('type', 'character'), ('letter', ['a', 'b', 'c', 'd'])]), OrderedDict([('type', 'integer'), ('number', ['1', '2', '3', '4'])])]

1
那应该可以运行:

lst = [OrderedDict([('type', t), (kind, [d.items()[1][1] for d in lst if d['type'] == t])]) for (t, kind) in set((d['type'], d.items()[1][0]) for d in lst)]

输出:

[OrderedDict([('type', 'integer'), ('number', ['1', '2', '3', '4'])]), OrderedDict([('type', 'character'), ('letter', ['a', 'b', 'c', 'd'])])]

0

如果想要一个更少使用列表推导式的答案(有时可以提高可读性),请参见:

from collections import OrderedDict

lst = [
    OrderedDict([('type', 'character'), ('letter', 'a')]),
    OrderedDict([('type', 'character'), ('letter', 'b')]),
    OrderedDict([('type', 'character'), ('letter', 'c')]),
    OrderedDict([('type', 'character'), ('letter', 'd')]),
    OrderedDict([('type', 'integer'), ('number', '1')]),
    OrderedDict([('type', 'integer'), ('number', '2')]),
    OrderedDict([('type', 'integer'), ('number', '3')]),
    OrderedDict([('type', 'integer'), ('number', '4')])
]

types_found = []  # using a list to maintain original order
types_dict = {}   # using a dict for speed and storage

for entry in lst:
    t = entry.get("type", "unknown")
    if t not in types_dict:
        types_found.append(t)
        types_dict[t] = OrderedDict([("type", t)])
    for k, v in entry.items():
        if k != "type":
            types_dict[t].setdefault(k, []).append(v)

new_list = [types_dict[t] for t in types_found]
# okay, so I did use one list comprehension, but it's a simple one :)

我假设上述内容是重要的:

  • 你可能有其他的“类型”条目,而不仅限于“字符”或“整数”;所以你需要一个开放式的解决方案。
  • 你希望保持在lst中找到的原始顺序。
  • 你的生产代码可能存在缺失的键;或者比预期更多的键。

这是使用Python 3.5编写的。对于一些旧版本,你可能需要用'.iteritems()'替换'.items()'。


回想起来,如果当初将types_dict设置为一个OrderedDict()而不是普通的字典,我就可以移除types_found的追踪以维护顺序。某种意义上讽刺。 - JohnAD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接