I have two lists of dictionaries like the ones below:
a = [
{'name': 'john', 'exam 1': 'python'},
{'name': 'chris', 'exam 1': 'java'},
{'name': 'newman', 'exam 1': 'C'},
{'name': 'sebast', 'exam 1': 'C#'},
{'name': 'penier', 'exam 1': 'python'},
{'name': 'alex', 'exam 1': 'go'},
{'name': 'steve', 'exam 1': 'C#'}
]
b = [
{'name': 'john', 'exam 2': 'django'},
{'name': 'newman', 'exam 2': 'java'},
{'name': 'sebast', 'exam 2': 'C'},
{'name': 'chris', 'exam 2': 'C#'}
{'name': 'penier', 'exam 2': 'python'},
{'name': 'steve', 'exam 2': 'go'},
{'name': 'alex', 'exam 2': 'C#'}
]
I would like to merge them in one dictionary like the one below:
c = [
{'name': 'john', 'exam 1': 'python', 'exam 2': 'django'},
{'name': 'chris', 'exam 1': 'java', 'exam 2': 'C#'},
{'name': 'newman', 'exam 1': 'C', 'exam 2': 'java'},
{'name': 'sebast', 'exam 1': 'C#', 'exam 2': 'C'},
{'name': 'penier', 'exam 1': 'python', 'exam 2': 'python'},
{'name': 'alex', 'exam 1': 'go', 'exam 2': 'C#'},
{'name': 'steve', 'exam 1': 'C#', 'exam 2': 'go'}
]
I have tried the following:
for i, j in zip(a, b):
if i['name'] == j['name']:
c.update(i)
The result I am getting is just one dictionary that adds those lines that are the same not if their location is different.
CodePudding user response:
You could create two lookup dictionaries for each list and then find the intersection:
import pprint
lookup_A = {d["name"]: d for d in A}
lookup_B = {d["name"]: d for d in B}
result = [{**value, **lookup_B.get(key, {})} for key, value in lookup_A.items()]
pprint.pprint(result)
Output
[{'exam 1': 'python', 'exam 2': 'django', 'name': 'john'},
{'exam 1': 'java', 'exam 2': 'C#', 'name': 'chris'},
{'exam 1': 'C', 'exam 2': 'java', 'name': 'newman'},
{'exam 1': 'C#', 'exam 2': 'C', 'name': 'sebast'},
{'exam 1': 'python', 'exam 2': 'python', 'name': 'penier'},
{'exam 1': 'go', 'exam 2': 'C#', 'name': 'alex'},
{'exam 1': 'C#', 'exam 2': 'go', 'name': 'steve'}]
CodePudding user response:
With pandas
you can do merge
pd.DataFrame(A).merge(pd.DataFrame(B), on='name').to_dict('records')
[{'name': 'john', 'exam 1': 'python', 'exam 2': 'django'},
{'name': 'chris', 'exam 1': 'java', 'exam 2': 'C#'},
{'name': 'newman', 'exam 1': 'C', 'exam 2': 'java'},
{'name': 'sebast', 'exam 1': 'C#', 'exam 2': 'C'},
{'name': 'penier', 'exam 1': 'python', 'exam 2': 'python'},
{'name': 'alex', 'exam 1': 'go', 'exam 2': 'C#'},
{'name': 'steve', 'exam 1': 'C#', 'exam 2': 'go'}]
CodePudding user response:
Though inefficient, here's a simple approach that is easy to follow, I suppose something like this was what you had in mind with your attempt using zip
.
for a in A:
for b in B:
if b['name'] == a['name']:
a.update(b)
C.append(a)
CodePudding user response:
I would iterate over the lists and do a lookup before adding as follows:
Benefit is greater control. Cost is O(n) where n is the length of b
# Start off with values being a
c_dict = {x['name']:x for x in a}
# 'Upsert' from new list of dicts
for x in b:
# You can update this to make this skip items not found in b
# or other similar operations
if not c_dict.get(x['name']):
c_dict[x['name']] = x
else:
c_dict[x['name']].update(x)
# Finally convert to a list
c = list(c_dict.values())