【问题标题】:How to merge multiple dicts with same key or different key?如何合并具有相同键或不同键的多个字典?
【发布时间】:2023-03-16 22:35:02
【问题描述】:

我有多个这样的字典/键值对:

d1 = {key1: x1, key2: y1}  
d2 = {key1: x2, key2: y2}  

我希望结果是一个新的字典(如果可能,以最有效的方式):

d = {key1: (x1, x2), key2: (y1, y2)}  

实际上,我希望结果 d 是:

d = {key1: (x1.x1attrib, x2.x2attrib), key2: (y1.y1attrib, y2.y2attrib)}  

如果有人告诉我如何获得第一个结果,我可以弄清楚其余的。

【问题讨论】:

  • @Salil:我们可以假设每个键都存在于所有字典中吗?
  • 嗨 Space_C0wb0y,是的,所有字典中都有键。
  • 指定所有字典是否具有相同的键是绝对关键的。

标签: python python-3.x dictionary merge


【解决方案1】:

使用下面的方法,我们可以合并两个具有相同键的字典。

def update_dict(dict1: dict, dict2: dict) -> dict:
output_dict = {}
for key in dict1.keys():
    output_dict.update({key: []})
    if type(dict1[key]) != str:
        for value in dict1[key]:
            output_dict[key].append(value)
    else:
        output_dict[key].append(dict1[key])
    if type(dict2[key]) != str:
        for value in dict2[key]:
            output_dict[key].append(value)
    else:
        output_dict[key].append(dict2[key])

return output_dict

输入:d1 = {key1: x1, key2: y1} d2 = {key1: x2, key2: y2}
输出:{'key1': ['x1', 'x2'], 'key2': ['y1', 'y2']}

【讨论】:

    【解决方案2】:

    pandas Data FrameIMO 更好地表示两个或多个具有相同键的字典:

    d1 = {"key1": "x1", "key2": "y1"}  
    d2 = {"key1": "x2", "key2": "y2"}  
    d3 = {"key1": "x3", "key2": "y3"}  
    
    d1_df = pd.DataFrame.from_dict(d1, orient='index')
    d2_df = pd.DataFrame.from_dict(d2, orient='index')
    d3_df = pd.DataFrame.from_dict(d3, orient='index')
    
    fin_df = pd.concat([d1_df, d2_df, d3_df], axis=1).T.reset_index(drop=True)
    fin_df
    
        key1 key2
    0   x1   y1
    1   x2   y2
    2   x3   y3
    

    【讨论】:

      【解决方案3】:

      即使两个字典中的键不同,这个函数也会合并两个字典:

      def combine_dict(d1, d2):
          return {
              k: tuple(d[k] for d in (d1, d2) if k in d)
              for k in set(d1.keys()) | set(d2.keys())
          }
      

      例子:

      d1 = {
          'a': 1,
          'b': 2,
      }
      d2` = {
          'b': 'boat',
          'c': 'car',
      }
      combine_dict(d1, d2)
      # Returns: {
      #    'a': (1,),
      #    'b': (2, 'boat'),
      #    'c': ('car',)
      # }
      

      【讨论】:

        【解决方案4】:

        假设有两个字典具有完全相同的键,下面是最简洁的方法(python3 应该用于两种解决方案)。

        
        d1 = {'a': 1, 'b': 2, 'c':3}
        d2 = {'a': 5, 'b': 6, 'c':7} 
        
        # get keys from one of the dictionary
        ks = [k for k in d1.keys()]
        
        print(ks)
        ['a', 'b', 'c']
        
        # call values from each dictionary on available keys
        d_merged = {k: (d1[k], d2[k]) for k in ks}
        
        print(d_merged)
        {'a': (1, 5), 'b': (2, 6), 'c': (3, 7)}
        
        # to merge values as list
        d_merged = {k: [d1[k], d2[k]] for k in ks}
        print(d_merged)
        {'a': [1, 5], 'b': [2, 6], 'c': [3, 7]}
        

        如果有两个字典有一些共同的键,但有几个不同的键,则应准备所有键的列表。

        
        d1 = {'a': 1, 'b': 2, 'c':3, 'd': 9}
        d2 = {'a': 5, 'b': 6, 'c':7, 'e': 4} 
        
        # get keys from one of the dictionary
        d1_ks = [k for k in d1.keys()]
        d2_ks = [k for k in d2.keys()]
        
        all_ks = set(d1_ks + d2_ks)
        
        print(all_ks)
        ['a', 'b', 'c', 'd', 'e']
        
        # call values from each dictionary on available keys
        d_merged = {k: [d1.get(k), d2.get(k)] for k in all_ks}
        
        print(d_merged)
        {'d': [9, None], 'a': [1, 5], 'b': [2, 6], 'c': [3, 7], 'e': [None, 4]}
        
        

        【讨论】:

          【解决方案5】:

          如果键是嵌套的:

          d1 = { 'key1': { 'nkey1': 'x1' }, 'key2': { 'nkey2': 'y1' } } 
          d2 = { 'key1': { 'nkey1': 'x2' }, 'key2': { 'nkey2': 'y2' } }
          
          ds = [d1, d2]
          d = {}
          for k in d1.keys():
              for k2 in d1[k].keys():
                  d.setdefault(k, {})
                  d[k].setdefault(k2, [])
                  d[k][k2] = tuple(d[k][k2] for d in ds)
          

          产量:

          {'key1': {'nkey1': ('x1', 'x2')}, 'key2': {'nkey2': ('y1', 'y2')}}
          

          【讨论】:

            【解决方案6】:

            假设您拥有所有键的列表(您可以通过遍历所有字典并获取它们的键来获取此列表)。让我们将其命名为listKeys。另外:

            • listValues 是您想要的单个键的所有值的列表 合并。
            • allDicts: 你要合并的所有字典。
            result = {}
            for k in listKeys:
                listValues = [] #we will convert it to tuple later, if you want.
                for d in allDicts:
                   try:
                        fileList.append(d[k]) #try to append more values to a single key
                    except:
                        pass
                if listValues: #if it is not empty
                    result[k] = typle(listValues) #convert to tuple, add to new dictionary with key k
            

            【讨论】:

              【解决方案7】:

              这个库帮助了我,我有一个嵌套键的字典列表,它们具有相同的名称但具有不同的值,所有其他解决方案都不断覆盖这些嵌套键。

              https://pypi.org/project/deepmerge/

              from deepmerge import always_merger
              
              def process_parms(args):
                  temp_list = []
                  for x in args:
                      with open(x, 'r') as stream:
                          temp_list.append(yaml.safe_load(stream))
              
                  return always_merger.merge(*temp_list)
              

              【讨论】:

                【解决方案8】:

                这是一个通用的解决方案,可以处理任意数量的字典,当键只在一些字典中时:

                from collections import defaultdict
                
                d1 = {1: 2, 3: 4}
                d2 = {1: 6, 3: 7}
                
                dd = defaultdict(list)
                
                for d in (d1, d2): # you can list as many input dicts as you want here
                    for key, value in d.items():
                        dd[key].append(value)
                
                print(dd)
                

                演出:

                defaultdict(<type 'list'>, {1: [2, 6], 3: [4, 7]})
                

                另外,要获取您的.attrib,只需将append(value) 更改为append(value.attrib)

                【讨论】:

                • 我认为 OP 想要的值是 tuple 而不是 list
                • @A A:真的很重要吗?在多个输入字典的更一般情况下构建元组将更加棘手,其中一些键不存在于任何地方,恕我直言
                • 然后您可能希望从defaultdict 中创建一个正常的dict,以便您对不存在的键等具有正常的dict 行为:dd = dict(dd)
                • @Ned:好点,但这取决于数据的最终用途
                • @Eli:不,这没关系,但我只是试图根据 OP 的要求,并希望你能找到元组的解决方案 :-)
                【解决方案9】:

                来自 blub 的回答:

                您也可以使用每个列表中的值直接形成元组

                ds = [d1, d2]
                d = {}
                for k in d1.keys():
                  d[k] = (d1[k], d2[k])
                

                如果您对元组有特定的顺序,这可能会很有用

                ds = [d1, d2, d3, d4]
                d = {}
                for k in d1.keys():
                  d[k] = (d3[k], d1[k], d4[k], d2[k]) #if you wanted tuple in order of d3, d1, d4, d2
                

                【讨论】:

                  【解决方案10】:

                  为了补充两个列表的解决方案,这里有一个处理单个列表的解决方案。

                  一个示例列表(NetworkX 相关;为便于阅读在此处手动格式化):

                  ec_num_list = [((src, tgt), ec_num['ec_num']) for src, tgt, ec_num in G.edges(data=True)]
                  
                  print('\nec_num_list:\n{}'.format(ec_num_list))
                  ec_num_list:
                  [((82, 433), '1.1.1.1'),
                    ((82, 433), '1.1.1.2'),
                    ((22, 182), '1.1.1.27'),
                    ((22, 3785), '1.2.4.1'),
                    ((22, 36), '6.4.1.1'),
                    ((145, 36), '1.1.1.37'),
                    ((36, 154), '2.3.3.1'),
                    ((36, 154), '2.3.3.8'),
                    ((36, 72), '4.1.1.32'),
                    ...] 
                  

                  注意相同边的重复值(由元组定义)。将这些“值”与它们对应的“键”进行比较:

                  from collections import defaultdict
                  ec_num_collection = defaultdict(list)
                  for k, v in ec_num_list:
                      ec_num_collection[k].append(v)
                  
                  print('\nec_num_collection:\n{}'.format(ec_num_collection.items()))
                  ec_num_collection:
                  [((82, 433), ['1.1.1.1', '1.1.1.2']),   ## << grouped "values"
                  ((22, 182), ['1.1.1.27']),
                  ((22, 3785), ['1.2.4.1']),
                  ((22, 36), ['6.4.1.1']),
                  ((145, 36), ['1.1.1.37']),
                  ((36, 154), ['2.3.3.1', '2.3.3.8']),    ## << grouped "values"
                  ((36, 72), ['4.1.1.32']),
                  ...] 
                  

                  如果需要,将该列表转换为字典:

                  ec_num_collection_dict = {k:v for k, v in zip(ec_num_collection, ec_num_collection)}
                  
                  print('\nec_num_collection_dict:\n{}'.format(dict(ec_num_collection)))
                    ec_num_collection_dict:
                    {(82, 433): ['1.1.1.1', '1.1.1.2'],
                    (22, 182): ['1.1.1.27'],
                    (22, 3785): ['1.2.4.1'],
                    (22, 36): ['6.4.1.1'],
                    (145, 36): ['1.1.1.37'],
                    (36, 154): ['2.3.3.1', '2.3.3.8'],
                    (36, 72): ['4.1.1.32'],
                    ...}
                  

                  参考文献

                  【讨论】:

                    【解决方案11】:

                    假设所有键始终存在于所有字典中:

                    ds = [d1, d2]
                    d = {}
                    for k in d1.iterkeys():
                        d[k] = tuple(d[k] for d in ds)
                    

                    注意:在 Python 3.x 中使用以下代码:

                    ds = [d1, d2]
                    d = {}
                    for k in d1.keys():
                      d[k] = tuple(d[k] for d in ds)
                    

                    如果 dic 包含 numpy 数组:

                    ds = [d1, d2]
                    d = {}
                    for k in d1.keys():
                      d[k] = np.concatenate(list(d[k] for d in ds))
                    

                    【讨论】:

                    • 我认为只要“for k in d1”就可以了。
                    • 和 d.get(k, None) 代替 d[k]
                    • @tahir 这意味着字典具有不匹配的键,因此迭代 d1 是不正确的(它可能会丢失其他字典中的键)。
                    • 对于 python 3 用户:d1.iterkeys() =d1.items()
                    • 它在 Python3.x 中仍然对我不起作用。即使我的值不是数组,我也试过这个,它可以工作。但是,输出的值将是数组。 stackoverflow.com/questions/54040858/…
                    【解决方案12】:
                    dict1 = {'m': 2, 'n': 4}
                    dict2 = {'n': 3, 'm': 1}
                    

                    确保键的顺序相同:

                    dict2_sorted = {i:dict2[i] for i in dict1.keys()}
                    
                    keys = dict1.keys()
                    values = zip(dict1.values(), dict2_sorted.values())
                    dictionary = dict(zip(keys, values))
                    

                    给出:

                    {'m': (2, 1), 'n': (4, 3)}
                    

                    【讨论】:

                    • values() 中的元素顺序未定义,因此您可能正在合并来自不相关键的值。
                    • 我刚刚应用了更改,因此它现在可以捕获您的反馈
                    • 我认为更改不会解决问题。您需要使用sorted(d.items())sorted(d.keys()) 来获得可预测的结果。
                    • 你能举个例子来证明这一点吗? dict2_sorted 是python中的排序字典!
                    • 我对此做了一个小的研究。在最新版本的 Python(3.6+)中,迭代顺序开始与插入顺序相匹配(参见例如here),这使您的代码通过。但这被认为是不应依赖的实现细节。我的第二个示例(请参阅here)在使用旧 Python 3.4 的onlinegdb 中确实失败了。其他在线解释器使用较新的 Python,因此无法在此处重现问题。
                    【解决方案13】:

                    Python 3.x 更新

                    来自 Eli Bendersky 的回答:

                    Python 3 删除了 dict.iteritems 改为使用 dict.items。 参见 Python 维基:https://wiki.python.org/moin/Python3.0

                    from collections import defaultdict
                    
                    dd = defaultdict(list)
                    
                    for d in (d1, d2):
                        for key, value in d.items():
                            dd[key].append(value)
                    

                    【讨论】:

                      【解决方案14】:

                      一个紧凑的可能性

                      d1={'a':1,'b':2}
                      d2={'c':3,'d':4}
                      context={**d1, **d2}
                      context
                      {'b': 2, 'c': 3, 'd': 4, 'a': 1}
                      

                      【讨论】:

                      • 问题是关于合并具有相同键的字典。你不是必需的答案。
                      【解决方案15】:
                      def merge(d1, d2, merge):
                          result = dict(d1)
                          for k,v in d2.iteritems():
                              if k in result:
                                  result[k] = merge(result[k], v)
                              else:
                                  result[k] = v
                          return result
                      
                      d1 = {'a': 1, 'b': 2}
                      d2 = {'a': 1, 'b': 3, 'c': 2}
                      print merge(d1, d2, lambda x, y:(x,y))
                      
                      {'a': (1, 1), 'c': 2, 'b': (2, 3)}
                      

                      【讨论】:

                        【解决方案16】:

                        这是您可以使用的一种方法,即使两个字典没有相同的键也可以使用:

                        d1 = {'a':'test','b':'btest','d':'dreg'}
                        d2 = {'a':'cool','b':'main','c':'clear'}
                        
                        d = {}
                        
                        for key in set(d1.keys() + d2.keys()):
                            try:
                                d.setdefault(key,[]).append(d1[key])        
                            except KeyError:
                                pass
                        
                            try:
                                d.setdefault(key,[]).append(d2[key])          
                            except KeyError:
                                pass
                        
                        print d
                        

                        这将生成以下输入:

                        {'a': ['test', 'cool'], 'c': ['clear'], 'b': ['btest', 'main'], 'd': ['dreg']}
                        

                        【讨论】:

                        • 可以将答案中的set(d1.keys() + d2.keys()) 更改为set(list(d1.keys()) + list(d2.keys()))(对于Python 3.x)吗?否则会在 python3.x 中抛出 TypeError: unsupported operand type(s) for +: 'dict_keys' and 'dict_keys' 错误
                        【解决方案17】:

                        如果你只有 d1 和 d2,

                        from collections import defaultdict
                        
                        d = defaultdict(list)
                        for a, b in d1.items() + d2.items():
                            d[a].append(b)
                        

                        【讨论】:

                          猜你喜欢
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2018-08-02
                          • 2019-11-19
                          • 2020-12-18
                          相关资源
                          最近更新 更多