Home > Net >  How to handle when key(s) do not exist in both dicts?
How to handle when key(s) do not exist in both dicts?

Time:07-20

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, ifs, 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
]
  • Related