问题
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:
- changing the keys in
objects
andsections
to be based on combination ofobject
andsemver
represented by a tuple. - 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