How to merge list of dictionaries?

喜夏-厌秋 提交于 2020-05-17 07:05:24

问题


I'm extending my original question here: How to append/merge list of dictionaries?.

I'm trying to merge some data between a single List of dictionaries that has lists inside. Merging would happen based on the "object" and "semver" key if they matched. Also adding to their given "section" if the same value was matched. Given the following data:

data = [
        {
         "semver":"1.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "add: comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
      {
         "semver":"1.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "add: Second comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
      {
         "semver":"1.0.0",
         "sections":[
            {
               "name":"Fix",
               "messages":[
                  "Comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
      {
         "semver":"2.0.0",
         "sections":[
            {
               "name":"Fix",
               "messages":[
                  "2.0.0 Fix Comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
      {
         "semver":"2.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "2.0.0 Add Comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
      {
         "semver":"2.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "2.0.0 comment for the NewFile"
               ]
            }
         ],
         "object":"NewFile.sh"
      },
]

I would like to achieve this as a end result

data = [
        {
         "semver":"1.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "add: comment here",
                  "add: Second comment here"
               ]
            },
            {
               "name":"Fix",
               "messages":[
                  "Fix: comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
        {
         "semver":"2.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "2.0.0 Add comment here",
               ]
            },
            {
               "name":"Fix",
               "messages":[
                  "2.0.0 Fix Comment here"
               ]
            }
         ],
         "object":"files.sh"
      },
      {
         "semver":"2.0.0",
         "sections":[
            {
               "name":"Add",
               "messages":[
                  "2.0.0 comment for the NewFile"
               ]
            }
         ],
         "object":"NewFile.sh"
      },

]

Code Block

objects = {}  # mapping for object: object_data with sections
sections = defaultdict(list)  # mapping for object: all sections
for d in data:
    print(d["semver"])
    for k, v in list(d.items()):
        if v == d["semver"]:
            try:
                section = d.pop("sections")
                sections[d["object"]].extend(section)
                objects[d["object"]] = d  # populate with object data without sections
            except Exception as e:
                print(e)
                pass

output = []
for object_name, object_data in objects.items():
    object_data["sections"] = sections[object_name]
    output.append(object_data)

So far I am looping through each k,v pair in the dict's but can't wrap my head around matching between the two versions and appending to that specific dict in the loop.


回答1:


There are 2 changes that should be done:

  1. changing the keys in objects and sections to be based on combination of object and semver represented by a tuple.
  2. add an auxiliary function to merge the messages in sections

Try this:

import json  # just for pretty print, you don't have to use it
from collections import defaultdict


def merge_messages(sections):
    d = defaultdict(list)
    for m in sections:
        d[m["name"]].extend(m["messages"])
    return [{"name": k, "messages": v} for k, v in d.items()]


objects = {}  # mapping for data with sections for (object, semver) combinations
sections = defaultdict(list)  # mapping for sections data for (object, semver) combinations
for d in data:
    section = d.pop("sections")
    sections[(d["object"], d["semver"])].extend(section)  # extends the sections for the object
    objects[(d["object"], d["semver"])] = d  # # populate with object data without sections

# merge between sections and objects by object key
output = []
for comb, object_data in objects.items():
    object_data["sections"] = merge_messages(sections[comb])
    output.append(object_data)
print(json.dumps(output, indent=4))  # just for pretty print


来源:https://stackoverflow.com/questions/61465107/how-to-merge-list-of-dictionaries

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!