I have two lists of python dictionnaries :
l1 = [{"id":1, "name":"A"}, {"id":2, "name":"B"}]
l2 = [{"id":1, "full_name":"Alfred"}, {"id":2, "full_name":"Barbara"}]
My goal is to have a list as follow :
l3 = [{"id":1, "full_name":"Alfred", "name":"A"}, {"id":2, "full_name":"Barbara", "name":"B"}]
I think I could use nested loops to do this, but I'm sure it should be possible to do it in a better and more pythonic way.
CodePudding user response:
from collections import defaultdict
res = defaultdict(dict)
for a, b in zip(l1, l2):
key1 = a['id']
key2 = b['id']
res[key1].update(a)
res[key2].update(b)
print(list(res.values())) # [{'id': 1, 'name': 'A', 'full_name': 'Alfred'}, {'id': 2, 'name': 'B', 'full_name': 'Barbara'}]
Although this would work in a single iteration you might want to simplify your underlying data structures a bit to make them easier to work with.
CodePudding user response:
Assuming you sort
the lists by the ID value in advance and that the ID values in the two lists are the same (just possibly in a different order), we can do it with a simple zip
call.
l1.sort(key=lambda x: x["id"])
l2.sort(key=lambda x: x["id"])
def merge(x, y):
a = {}
a.update(x)
a.update(y)
return a
l3 = [merge(x, y) for x, y in zip(l1, l2)]
Note that in Python 3.9 and newer, merge
is simply |
, so we can write
l3 = [x | y for x, y in zip(l1, l2)]
and eliminate the need for the helper function altogether.
CodePudding user response:
l1 = [{"id":1, "name":"A"}, {"id":2, "name":"B"}]
l2 = [{"id":1, "full_name":"Alfred"}, {"id":2, "full_name":"Barbara"}]
print([{**i,**j} for i in l1 for j in l2 if i["id"] ==j["id"]])
Result:
[{'id': 1, 'name': 'A', 'full_name': 'Alfred'}, {'id': 2, 'name': 'B', 'full_name': 'Barbara'}]
you could try something like this, which you maybe already knew ... would be interesting to see something more pythonic :)
CodePudding user response:
I'd suggest restructuring your input data when creating it, so that id
is an actual identifier for each specific person. If you make value of id
key for an outer dictionary, you can do it in a single pass through one each of the mappings.
from collections import defaultdict
l1 = {1:{"name":"A"}, 2:{"name":"B"}, 3:{"name":"C"}}
l2 = {1:{"full_name":"Alfred"}, 2:{"full_name":"Barbara"}}
result = defaultdict(dict)
for li in [l1, l2]:
for k,v in li.items():
result[k].update(v)
print(result)
(I removed the "id":value
from the data because it's redundant with this form of data but adding it back in should be no problem if you really need it there.)
CodePudding user response:
Use the id as identifer, create new dicts and update them - more comments in code.
No sorting needed, un"even" source lists inner dicts will be kept as well
l1 = [{"id":1, "name":"A"}, {"id":2, "name":"B"}]
l2 = [{"id":1, "full_name":"Alfred"}, {"id":2, "full_name":"Barbara"}]
# intermediate dictionary that keeps all collected inner dicts at the id
d = {}
# go through both lists
for inner_d in l1 l2:
# create a new empty dict under the id if needed
what = d.setdefault(inner_d["id"], {})
# add all things from the inner dict
what.update(inner_d.items())
as_list = list(d.values())
print(as_list)
Output:
[{'id': 1, 'name': 'A', 'full_name': 'Alfred'},
{'id': 2, 'name': 'B', 'full_name': 'Barbara'}]
CodePudding user response:
In one line (assuming id fields have perfect 1:1 mapping) :
result = [x | y for x, y in zip(sorted(l1, key = lambda x: x['id']), sorted(l2, key = lambda x: x['id']) )]