I'm trying to find a way to merge two dicts, but I'm not getting it to handle with KeyError
. I already tried to insert a try
/except
, if
s, and nothing works.
This a example of two lists/dicts:
list1 = [ {"Name":"Paul", "age": 34, "brothers": ["Sam","Cris","Jack"] } ,
{"Name":"Evan", "age": 14, "brothers": ["N/A"] } ,
{"Name":"Loki", "age": 4, "brothers": ["Thor"] } ]
list2 = {"Sam":["ice_cream"], "Loki": ["cars"], "Jack": ["fruits","cars"],
"Cris": ["ice_cream"] }
Keep in mind that that values are dump of extensive lists, I cannot erase on hands.
What is happening here: There are values which list2
will not have and some cases, list1
will show a "N/A".
I'm interested in creating this output: creating a new info
key and add respective values without repeation, like:
[
{"Name": "Paul", "age": 34, "brothers": ["Sam","Cris","Jack"],
info: ["icre_cream, "fruis", "cars"]} ,
{"Name": "Evan", "age": 14, "brothers": ["N/A"], info: []},
{"Name": "Loki", "age": 4, "brothers": ["Thor"], info: []}
]
But trying to iteract, KeyError
are being raised.
newList = [
{**d, "Ids": sorted(set(i for t in d["brothers"] for i in list2[t]))}
for d in list1
]
CodePudding user response:
You can use a set comprehension with two for
clauses to merge the info of each brother. Use the dict.get
method with a default value of an empty tuple to avoid a KeyError
due to the non-existent key of 'N/A'
:
[
{**d, 'info': sorted({i for b in d['brothers'] for i in list2.get(b, ())})}
for d in list1
]
Demo: https://replit.com/@blhsing/GlamorousRespectfulWebsphere
CodePudding user response:
You can do something like this:
def merged(list1, list2):
new_list = []
for person in list1:
extra_info = list(set(sum([list2.get(name, []) for name in person["brothers"]], [])))
person["info"] = extra_info
new_list.append(person)
return new_list
The new_list
list is your expected output. Note that I called it list2
here because that's what you named it, but your second input is actually just a dictionary and not a list.
Using list2.get(name, [])
allows you to return list2[name]
if the key exists in list2
and returns []
if it doesn't.
Just for kicks since you seem to want a one-liner here, you can define the same merged
function above like so:
merged = lambda l1, l2: [
{**d, "info": sum([l2.get(n, []) for n in d["brothers"]], [])} for d in l1
]
newList = merged(list1, list2)
Edit:
As pointed out in the comments, using sum
and aggregating the lists before converting them to sets (and back to lists) is very inefficient, albeit more easily readable. You can use functools.reduce
to get something more efficient (if you even care):
import functools
merged = lambda l1, l2: [
{
**d,
"info": list(
functools.reduce(
lambda a, b: a.union(b),
[set(l2.get(n, [])) for n in d["brothers"]],
set(),
)
),
}
for d in l1
]