【问题标题】:Pythonic way to merge keys with common values for a single dictionary将键与单个字典的公共值合并的 Pythonic 方法
【发布时间】:2017-12-12 22:46:08
【问题描述】:

如何将具有公共值的字典键合并到元组中。例如:

A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

output = {('E2', 'E5'): {'5', '7'}, ('E3', 'E8'): {'4', '8'}}

我的尝试:

A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

output = {}
seen = []
for k, v in A.items():
    if v not in [s[1] for s in seen]: # not seen this value yet
        print('NOT SEEN')
        print(k, v)
        seen.append([k,v])
        output[k] = v
    else: # already seen it 
        print('SEEN')
        print(k, v)
        # determine where we've seen it 
        where = [x for x in seen if x[1]==v]
        output.pop(where[0][0])
        output[(where[0][0], k)] = v


print('OUTPUT = ', output)       

打印出来:

OUTPUT =  {('E2', 'E5'): {'7', '5'}, ('E3', 'E8'): {'4', '8'}}

【问题讨论】:

  • 好的,是什么阻止你这样做?您有具体问题吗?
  • @vaultah 改写为一个问题
  • 我们是说我们希望看到您的努力。 “给我代码”之类的问题通常不受欢迎。尤其是当一两个循环应该足以解决问题时。
  • @ApplePie 不一样

标签: python algorithm python-3.x dictionary merge


【解决方案1】:

我会分两次进行转换:

>>> A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}

# First pass:  Create a reverse one-to-many mapping. 
# The original set() value gets converted to a hashable frozenset()
# and used as a key.  The original scalar string key gets accumulated
# in a list to track the multiple occurrences.
>>> reverse = {}
>>> for key, value in A.items():
        reverse.setdefault(frozenset(value), []).append(key)

# Second pass:  reverse the keys and values.  The list of matching
# values gets converted to a hashable tuple (as specified by the OP)
# and the frozenset() gets restored back to the original set() type.
>>> {tuple(value) : set(key) for key, value in reverse.items()}
{('E2', 'E5'): {'5', '7'}, ('E3', 'E8'): {'8', '4'}}

这给出了 OP 预期的输出。

请注意,输入字典没有保证顺序,原始输入中的任何集合也没有。因此,输出不能有保证的术语顺序。

【讨论】:

    【解决方案2】:

    你可以试试这个:

    from collections import defaultdict
    
    A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
    
    second_new = defaultdict(list)
    
    for a, b in A.items():
        second_new[tuple(b)].append(a)
    
    final_dict = {tuple(b):set(a) for a, b in second_new.items()}
    

    输出:

    {('E8', 'E3'): {'8', '4'}, ('E5', 'E2'): {'5', '7'}}
    

    【讨论】:

    • 谢谢。这是最简单易懂的。
    • 很高兴能帮上忙。
    • 给了你最佳答案
    【解决方案3】:
    import itertools
    
    A = {'E2': {'5', '7'}, 'E3': {'4', '8'}, 'E5': {'5', '7'}, 'E8': {'4', '8'}}
    
    def key(x): 
        # List supports ordering
        return sorted(list(x[1]))
    
    def gen():
        for (group_key, group) in itertools.groupby(sorted(A.items(), key=key), key=key):
            gl = list(group)
            yield (tuple(x[0] for x in gl), 
                   gl[0][1]  # group_key is a list, but we want original set
                  )
    
    print(dict(gen()))
    

    如果您准备好说服自己 set->list->set 转换是安全的,那么您可以制作单行代码而不是生成器:

    print(dict((tuple(g[0] for g in group), set(group_key)) for 
               (group_key, group) in 
               itertools.groupby(sorted(A.items(), key=key), key=key)))
    

    UPD:那么,这里到底发生了什么?

    首先,我们通过调用.items() 将dict 转换为可迭代的元组。 我们希望将这个具有相同第二个元素(索引为 1,或前一个 dict 值)的可迭代项组合在一起。 这正是itertools.groupby 所做的。参数是我们将分组的可迭代和键。看来,key=lambda kv: kv[1] 是要走的路。不幸的是没有。我们可以比较集合是否相等,但是文档说应该对可迭代对象进行排序。并且sorted 功能需要键可比较的顺序。不能按列表比较集合的顺序。我们可以安全地创建一个包含与 set 相同元素的列表,但我们应该对其进行排序(相等的集合可以生成具有不同顺序的列表,{5, 7} == {7, 5},但 [5, 7] != [7, 5])。

    现在,经过排序和分组后,我们有以下数据结构:

    [
       (key_dict_value as list, iterable of (dict_key, dict_value) that has dict_value == key_dict_value),
       ...
    ]
    

    现在我们可以迭代这个可迭代对象并创建另一个元组可迭代对象。我们获取每个元组的第二个元素(可迭代,索引为 1)并将其转换为元组(这是我们未来字典的键)。我们未来字典的值是原始字典的值。我们可以从元组的第二个元素的某个元素中获取它(这个迭代不能为空,因为groupby 不能产生空组,请参阅第一个 sn-p)或从 key_dict_value 通过将其转换回列表(它是安全的,因为这个列表是从集合中产生的,所以它没有相等的元素,参见第二个 sn-p)。

    UPD2

    当我在写解释时,我发现相等的键不适用于sorted,但适用于groupby,所以这里有一个更简单的解决方案,无需定义key 函数并将列表转换回集合:

    print(dict((tuple(g[0] for g in group), group_key) for 
               (group_key, group) in itertools.groupby(sorted(A.items(), 
                                                              key=lambda x: sorted(list(x[1]))), 
                                                       key=lambda x: x[1])))
    

    【讨论】:

      【解决方案4】:

      这是我使用推导式完成的。只需要两个中间步骤,并且只使用内置数据类型。

      # get unique values from original dict
      targ_values = set([tuple(v) for v in A.values()])
      
      # build lists of original keys that match the temp_keys
      targ_values = {targ_value:[orig_key for orig_key, orig_value in A.items() if tuple(orig_value) == targ_value] for targ_value in targ_values}
      
      # reverse the order of keys & values and convert types to get desired output
      output = {tuple(v):set(k) for k, v in targ_values.items()}
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-08-05
        • 2014-10-13
        • 1970-01-01
        • 2015-04-22
        • 1970-01-01
        • 2019-11-11
        • 1970-01-01
        • 2017-11-07
        相关资源
        最近更新 更多