用相同的键组合两个或多个字典

时间:2019-05-08 06:34:49

标签: python python-3.x dictionary list-comprehension

我有两个词典项目 u_items

items = {"A": 1, "B": 2, "C": 3}

u_items = {"D": 4, "B": 4, "E": 8, "C": 4}

我想用u_items更新项目字典,所以我做到了

items.update((k + '_1' if k in items else k, v) for k, v in u_items.items())

这样我就可以区分两个字典的键

输出:

items = {'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4}

但是当我用另一个字典更新item字典时,假设n_items,它将替换B_1的值而不是将其设为B_1_1

n_items = {"C":7, "B":9}

items.update((k + '_1' if k in items else k, v) for k, v in n_items.items())

输出:

{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 9, 'E': 8, 'C_1': 7}

但是我希望输出像这样:

{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'B_1_1':9,'C_1_1':7}

或类似这样:

{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'B_2':9,'C_2':7}

我该怎么办?

7 个答案:

答案 0 :(得分:2)

您可以迭代地执行此操作:

def combine(*args):
    result = {}
    for d in args:
        for key, value in d.items():
            key = str(key)
            while key in result:
                key += '_1'
            result[key] = value

    return result

print(combine(items, u_items, n_items))

输出:

{'A': 1,
 'B': 2,
 'C': 3,
 'D': 4,
 'B_1': 4,
 'E': 8,
 'C_1': 4,
 'C_1_1': 7,
 'B_1_1': 9}

答案 1 :(得分:1)

尽管这似乎有点像 XY问题,但这是一个丑陋的问题(我很确定,效率很低),而且不是由以下组成的通用解决方案:

合并字典,方法是根据您的要求,在现有键上附加“ _1 ”(一行完成),尽管我建议(由于某些情况下最短的不一定是最好的):

  • 使用函数(以避免重复代码(表达式))
  • dict 进行子类化,并覆盖其 update 方法(上一个方法的更好的变体)
>>> items = {"A": 1, "B": 2, "C": 3}
>>> u_items = {"D": 4, "B": 4, "E": 8, "C": 4}
>>> n_items = {"C": 7, "B": 9}
>>>
>>> items.update((max([k1 + "_1" for k1 in items if k1 == k or k1.startswith(k + "_1")], key=len, default=k), v) for k, v in u_items.items())
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4}
>>>
>>> items.update((max([k1 + "_1" for k1 in items if k1 == k or k1.startswith(k + "_1")], key=len, default=k), v) for k, v in n_items.items())
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'C_1_1': 7, 'B_1_1': 9}
>>>
>>>
>>> # Merging an additional dictionary
...
>>> v_items = {"C": 25}
>>>
>>> items.update((max([k1 + "_1" for k1 in items if k1 == k or k1.startswith(k + "_1")], key=len, default=k), v) for k, v in v_items.items())
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'C_1_1': 7, 'B_1_1': 9, 'C_1_1_1': 25}

答案 2 :(得分:0)

使用operator.itemgetter

items = {'A':1, 'B':2, 'C':3}
u_items = {'D':4, 'B':4, 'E':8, 'C':4}
n_items = {"C":7, "B":9}

def update_dict(d1, d2):
    l = list(map(itemgetter(0), d1))
    d1.update(('_'.join([k,str(l.count(k))]) if k in l else k, v) 
             for k,v in d2.items())

update_dict(items, u_items)
update_dict(items, n_items)

使用u_items进行第一次更新时的输出:

{'A': 1, 'B': 2, 'B_1': 4, 'C': 3, 'C_1': 4, 'D': 4, 'E': 8}

使用n_items在第二次更新时输出:

{'A': 1,
 'B': 2,
 'B_1': 4,
 'B_2': 9,
 'C': 3,
 'C_1': 4,
 'C_2': 7,
 'D': 4,
 'E': 8}

答案 3 :(得分:0)

您可以使用一个小的助手功能:

d1 = {'A':1, 'B':2, 'B_1':3, 'B_1_1':4}
d2 = {'A':1, 'B':2}

def gen_key(key, dct):
    while key in dct:
        key += '_1'
    return key

d1.update((gen_key(k, d1), v) for k, v in d2.items())

print(d1)
# {'A': 1, 'B': 2, 'B_1': 3, 'B_1_1': 4, 'A_1': 1, 'B_1_1_1': 2}

答案 4 :(得分:0)

发布者的更新方法和if / else列表理解是一个很好的开始。 我认为关键是(请问双关语)是引入一个循环来找到可以接受的密钥。它是python3,但可以为此而复活化简,使其成为单线:

>>> import functools
>>> items = {"A": 1, "B": 2, "C": 3}
>>> u_items = {"D": 4, "B": 4, "E": 8, "C": 4}
>>> n_items = {"C":7, "B":9}
>>> items.update({functools.reduce(lambda c, n: c+n if c in items else c, ['_1']*2, k):*3 v for k, v in u_items.items()})
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4}
>>> items.update({functools.reduce(lambda c,n: c+n if c in items else c, ['_1']*2, k): v for k, v in n_items.items()})
>>> items
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'C_1_1': 7, 'B_1_1': 9}

请注意-渐进扩展名['_1']*2的列表必须与您要合并的列表数一样长。如果需要像C_1, C_2, ...这样的键,则可以构造一个更有趣的lambda。

答案 5 :(得分:0)

尝试一下

没有功能,没有任何模块,

>>> for k, v in n_items.items():
...   _k = {k: v}
...   if k in items:
...      _k = {max(i for i in items if k in i)+'_1': v}
...   items.update(_k)
... 
>>> items
{'A': 1, 'D': 4, 'B_1': 4, 'B': 2, 'D_1': 5, 'X': 1, 'C_1_1': 7, 'C': 3, 'E': 8, 'C_1': 4, 'B_1_1': 9}
>>> 

答案 6 :(得分:0)

由于我们通过添加 _count 来处理重复项,例如 next 是 C_1 我们只需要检查第一个字符 lambda x:x.startswith(key[0]) 基本上遍历 result.keys() 并检查是否有任何共享第一个字符 所以如果键有 C 和 C_1 ,我们会得到一个 2 的列表 一旦我们有了那个,该列表的长度将是下一个 C 的计数,即 len('C', 'C_1') 是 2,因此接下来我们有 'C_2'

def combine(*args):
    result = {}
    for d in args:
        for key, value in d.items():
            key = str(key)
            if key in result:
                keys = filter( lambda x:x.startswith(key[0]), result.keys())
                keys = len(list(keys))
                key = f'{key}_{keys}'
            result[key] = value

    return result

items = {"A": 1, "B": 2, "C": 3}

u_items = {"D": 4, "B": 4, "E": 8, "C": 4}

n_items = {"C":7, "B":9}

print(combine(items, u_items, n_items))
{'A': 1, 'B': 2, 'C': 3, 'D': 4, 'B_1': 4, 'E': 8, 'C_1': 4, 'C_2': 7, 'B_2': 9}

[Program finished]