【问题标题】:How to combine values composed of lists with common items in a dictionary using Python?如何使用 Python 将由列表组成的值与字典中的常见项目组合?
【发布时间】:2015-08-12 21:03:55
【问题描述】:

我有一本类似于以下内容的字典:

dict1 = {'key1':['1','2','3'],'key2':['3','4','5'],'key3':['6','7','8']}

我想合并所有至少有一个公共元素的键,结果是。例如,结果字典应如下所示:

dict1 = {'key1':['1','2','3','4','5'],'key3':['6','7','8']}

请注意 key2 是如何被消除的。被淘汰的是key1还是key2都没有关系。 我只能识别重复,但不知道如何以迭代方式合并它们。谢谢

【问题讨论】:

  • 如果 key2 和 3 共享例如值 4 怎么办?
  • 为什么是 key1 而不是 key2? dicts 没有顺序,所以不能保证先出现什么键
  • @Padraic,因为它们的值中有一个共同的项目('3'),所以 key3 中的所有项目对 key3 都是唯一的,因此它保持独立
  • 是的,但是为什么 key1 仍然存在而你删除了 key2?
  • key1 或 key2 都应该被删除。我不在乎哪个

标签: python list dictionary merge set-union


【解决方案1】:

这对你有用吗?请注意,由于字典中元素的顺序是任意的,因此您无法保证最终会将哪些键插入到输出字典中。

dict_out = {}
processed = set()
for k1, v1 in dict_in.items():
    if k1 not in processed:
        processed.add(k1)
        vo = v1
        for k2, v2 in dict_in.items():
            if k2 not in processed and set(v1) & set(v2):
                vo = sorted(list(set(vo + v2)))
                processed.add(k2)
        dict_out[k1] = vo

这用于:

dict_in = {'key1': ['1', '2', '3'], 'key2': ['3', '4', '5'], 'key3': ['6', '7', '8']}

给予:

{'key1': {'1', '2', '3', '4', '5'}, 'key3': ['6', '7', '8']}

对于:

dict_in = {'key1': ['1', '2', '3'], 'key2': ['3', '4', '5'],
           'key3': ['6', '7', '8'], 'key4': ['7', '9']}

给出:

{'key1': {'1', '2', '3', '4', '5'}, 'key3': {'6', '7', '8', '9'}}

最后,对于:

dict_in = {'key1': ['1', '2', '3'], 'key2': ['3', '4', '5'],
           'key3': ['6', '7', '8'], 'key4': ['5', '6', '7']}

它给出:

{'key1': {'1', '2', '3', '4', '5'}, 'key3': {'5', '6', '7', '8'}}

编辑

OP 要求即使是合并的结果也应该相互合并。为此,我们可以将上面的代码包装在这样的循环中:

d = dict_in
processed = set([None])
while processed:
    dict_out = {}
    processed = set()
    for k1, v1 in d.items():
        if k1 not in processed:
            vo = v1
            for k2, v2 in d.items():
                if k1 is not k2 and set(vo) & set(v2):
                    vo = sorted(list(set(vo + v2)))
                    processed.add(k2)
            dict_out[k1] = vo
    d = dict_out

那么,对于:

dict_in = {'key1': ['1', '2', '3'], 'key2': ['3', '4', '5'],
           'key3': ['6', '7', '8'], 'key4': ['5', '6', '7']}

我们得到:

{'key4': ['1', '2', '3', '4', '5', '6', '7', '8']}

对于:

dict_in = {'key1': ['1', '2', '3'], 'key2': ['3', '4', '5'],
           'key3': ['4', '6', '7'], 'key4': ['8', '9']}

我们得到:

{'key1': ['1', '2', '3', '4', '5', '6', '7'], 'key4': ['8', '9']}

【讨论】:

  • 试试dict_in = {'key1': ['1', '2', '3'], 'key2': ['3', '4', '5'], 'key3': ['6', '7', '8'],'key4': ["9","10"]}
  • 给予:{'key1': ['1', '2', '3', '4', '5'], 'key3': ['6', '7', '8'], 'key4': ['9', '10']}。这不正确吗?
  • 这非常适合合并一次,但是之前合并的键/值对不能与其他的合并。例如:dict_in = {'key1':['1','2','3'],'key2':['3','4','5'],'key3':['4' ,'6','7'],'key4':['8','9']} 这给出: {'key3': set(['8', '3', '5', '4' , '7']), 'key1': ['1', '2', '3'], 'key4': ['9', '10']} 这是不对的,因为 key1 和 key3 都有 3在他们之中。这么近!
  • 这种行为是故意的 :) 我认为这是您真正需要的。小的修改将解决它。
【解决方案2】:

如果要更改原始字典,则需要复制:

vals = {k: set(val) for k, val in dict1.items()}

for key, val in dict1.copy().items():
    for k, v in vals.copy().items():
        if k == key:
            continue
        if v.intersection(val):
            union = list(v.union(val))
            dict1[key] = union
            del vals[k]
            del dict1[k]

如果你想联合所有:

vals = {k: set(val) for k, val in dict1.items()}
unioned = set()
srt = sorted(dict1.keys())
srt2 = srt[:]
for key in srt:
    for k in srt2:
        if k == key:
            continue
        if vals[k].intersection(dict1[key]) and key not in unioned:
            unioned.add(k)
            dict1[key] = list(vals[k].union(dict1[key]))
            srt2.remove(k)

for k in unioned:
    del dict1[k]

【讨论】:

  • 我喜欢这个答案,效果很好。不过,Andrzej 是第一个……感谢您的努力和帮助。
  • @Vincem 不用担心,我不完全确定更新值后会发生什么,我添加了另一种处理方式
【解决方案3】:

我有一个更紧凑的方法。

我认为它更具可读性和易于理解。可以参考如下:

dict1 = {'key1':['1','2','3'],'key2':['3','4','5'],'key3':['6','7','8']}

# Index your key of dict
l = list(enumerate(sorted(dict1.keys())))

# nested loop
for i in xrange(len(dict1)):
    for j in xrange(i+1,len(dict1)):
        i_key, j_key = l[i][1], l[j][1]
        i_value, j_value = set(dict1[i_key]), set(dict1[j_key])
        # auto detect: if the values have common element to do union
        if i_value & j_value:
            union_list = sorted(list(i_value | j_value))
            dict1[i_key] = union_list
            del dict1[j_key]

print dict1
#{'key3': ['6', '7', '8'], 'key1': ['1', '2', '3', '4', '5']}

【讨论】:

    猜你喜欢
    • 2011-04-21
    • 2013-09-11
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 2023-01-27
    • 1970-01-01
    • 2020-04-01
    • 2021-12-01
    相关资源
    最近更新 更多