将基于公共密钥值的多个字典组合到一个字典中

时间:2016-12-07 14:54:50

标签: python dictionary merge

基本上我有一个OrderedDicts列表;

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 个答案:

答案 0 :(得分: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'])])]

答案 1 :(得分:1)

考虑到您的词典列表已经排序,您可以直接使用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'])])]

答案 2 :(得分: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 :)

对于上述情况,我假设以下内容很重要:

  • 您可能有其他'type'条目,而不是'character'或'integer';所以你想要一个开放式的解决方案。
  • 您希望维护lst中找到的原始订单。
  • 您的生产代码可能缺少密钥;或多于预期的钥匙。

这是用Python 3.5编写的。对于某些旧版本,您可能必须将'.items()'替换为'.iteritems()'。