【问题标题】:How to merge dicts when sharing common value?共享共同价值时如何合并字典?
【发布时间】:2020-12-12 11:47:26
【问题描述】:

我目前从我的数据库中删除了以下数据(4 个字典列表):

raw_data = [{'budget_id': 1, 'name': 'Maria', 'amount': 980, 'user': '10', 'gift': 'Phone', 'cost': 325}, {'budget_id': 1, 'name': 'Maria', 'amount': 980, 'user': '10', 'gift': 'Flower', 'cost': 195}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Paris Trip', 'cost': 599}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Ring', 'cost': 1200}]

我想自动合并共享相同“budget_id”的每个字典,以便最终得到以下结果(2 个字典列表):

final_data = [{'name': ['Maria'], 'cost': [195, 325], 'gift': ['Phone', 'Flower'], 'budget_id': [1], 'user': ['10'], 'amount': [980]}, {{'name': ['Scott'], 'cost': [599, 1200], 'gift': ['Paris Trip', 'Ring'], 'budget_id': [2], 'user': ['10'], 'amount': [2100]}

这个想法是它不应该被硬编码,因为从网站传入的字典数量会逐渐移动并减少加班时间。

到目前为止,我已经设法找到一个硬编码的解决方案,让我可以成功地合并第一和第二个字典:

Merge_Init = {}
for key in (fibud.keys() | sebud.keys()):
    if key in final_data[0]: Merge_Init.setdefault(key, []).append(final_data[0][key])
    if key in final_data[1]: Merge_Init.setdefault(key, []).append(final_data[1][key])
print(Merge_Init)

final_merge = {a:list(set(b)) for a, b in Merge_Init.items()}
print("New Dict without Duplicates:", final_merge)

导致:

New Dict without Duplicates: {'user': ['10'], 'gift': ['Phone', 'Flower'], 'name': ['Maria'], 'amount': [980], 'budget_id': [1], 'cost': [195, 325]}

请注意,在这种情况下,礼物的成本有些倒置,成本应该是 [325, 195]。

您能否协助找到一个解决方案来循环遍历每个预算并在它们共享相同的budget_id 时合并它们,而无需像“final_data[0]”这样的硬编码解决方案,同时保持数据完整性?

非常感谢!

【问题讨论】:

    标签: python list dictionary for-loop


    【解决方案1】:

    此解决方案不会对数组的任何元素进行硬编码,但由于您对不同的键有不同的要求,因此需要对这些键进行硬编码才能正确处理它们。 在合并后的示例中,您只有 ['Maria'],而如果您有两个项目的成本相同,那么您肯定会期望成本为 [150, 150],而不是 [150]。

    final = {} # key is budget_id, and value is the all dictionaries merged 
    for dict in list:
       budget_id = dict['budget_id']
       if budget_id in final:
            # for each key you'll do something like this
            dictToModify = final[budget_id]
            dictToModify.append(dict['gift'])
            # for each key in dictionary, add it to the list
            # some will be added always to the list: e.g. cost
            # some will be added only once, e.g. name and budget_id
    
       else:
           # here you're just putting everything in a list as in your final_data example
           final[ budget_id ] = {key:[value] for (key,value) in dict.items()}
    
    final_data = list(final.values())
    

    如果元素不存在,则此循环将元素添加到最终字典中,或者如果具有相同budget_id 的元素已经存在,则合并。 循环的最后一步是将其转换为字典列表。

    【讨论】:

      【解决方案2】:

      这是一种解决方案,扩展了raw_data 以获得更好的演示效果:

      raw_data = [{'budget_id': 1, 'name': 'Maria', 'amount': 980, 'user': '10', 'gift': 'Phone', 'cost': 325}, {'budget_id': 1, 'name': 'Maria', 'amount': 980, 'user': '10', 'gift': 'Flower', 'cost': 195}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Paris Trip', 'cost': 599}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Ring', 'cost': 1200}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Watch', 'cost': 240}]
      
      final_data = []
      
      for entry in raw_data:
      
          found = False
          for ind, final in enumerate(final_data):
              # Look if the budget entry already exists
              if entry['budget_id'] in final['budget_id']:
                  found = True
                  break
      
          if found:
              # Merge
              # Everything - issue if any entry just happens 
              # to be the same (like cost)
              #for key, value in entry.items():
                  #if not (entry[key] in final[key]):
                  #   final_data[ind][key].append(entry[key])
      
              # Alternative - specific entries only
              final_data[ind]['gift'].append(entry['gift'])
              final_data[ind]['cost'].append(entry['cost'])
          else:
              # If not yet there - add it as a new item, converting 
              # all values to lists
              final_data.append({x:[y] for x,y in entry.items()})
      
      print(final_data)
      

      代码循环遍历raw_data 循环中的所有字典。对于每个字典,它会循环遍历final_data 的所有现有条目,并使用enumerate 跟踪索引。使用budget_id 它检查是否已经遇到并存储了预算条目。如果是这种情况,它会设置一个适当的标志并中断循环。

      在第二部分中,如果尚未遇到条目,则将其作为字典附加到 final_data 列表中,并将其所有值转换为列表。

      如果它已经存在 - 数据将被合并。这里有两个选项,一个是注释掉的选项 - 如果值不相同/尚未存在,它将所有内容合并在一起。这对于商品价格等容易重复的东西不利,但为了完整起见,我将其保留。

      在第二个当前版本中,它只是查找特定的项目键并与它们合并。这假设即使gifts 中有重复项,也应该包含它们。

      【讨论】:

        【解决方案3】:

        你可以像这样使用熊猫:

        import pandas as pd
        
        df = pd.DataFrame([{'budget_id': 1, 'name': 'Maria', 'amount': 980, 'user': '10', 'gift': 'Phone', 'cost': 325}, {'budget_id': 1, 'name': 'Maria', 'amount': 980, 'user': '10', 'gift': 'Flower', 'cost': 195}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Paris Trip', 'cost': 599}, {'budget_id': 2, 'name': 'Scott', 'amount': 2100, 'user': '10', 'gift': 'Ring', 'cost': 1200}])
        df = df.groupby('budget_id').agg({'name': set,
                                           'amount': set,
                                           'cost': set ,
                                           'user': set,
                                           'gift': set}).reset_index()
        print(df.to_dict('records'))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-06-20
          • 2012-10-18
          • 1970-01-01
          • 2016-01-20
          • 2011-06-18
          • 1970-01-01
          相关资源
          最近更新 更多