Home > Back-end >  Python: merging 2 dictionaries (from csv file) with same key AND values
Python: merging 2 dictionaries (from csv file) with same key AND values

Time:05-07

I have these two DictReader-ed csv files:

A = {"Name": "Alex", "Age": 17} {"Name": "Bob", "Age": 20"} {"Name": "Clark", "Age": 24"}
B = {"Age": 17, "Class": "Economy"} {"Age": 24, "Class": "IT"} {"Age":17, "Class": Arts}

and several more bracketed values.

Is it possible to join them to form this:

{"Name": "Alex", "Age": 17, "Class": [{"Economy"}, {"Arts"}]}
{"Name": "Clark", "Age": 24, "Class": [{"IT"}]}

In short, joining them when they have the same Age and put all the same classes into a list?

So far I've only read both dicts:

import csv

A=open('A.csv')
A_reader = csv.DictReader(A)
B=open('B.csv')
B_reader = csv.DictReader(B)

for item in A_reader:
   print(item)

for item in B_reader:
   print(item)

but unsure of how to merge them as mentioned.

Thank you!

EDIT: The csv given is so that no two people will have the same age.

CodePudding user response:

import copy
A = [{"Name": "Alex", "Age": 17}, {"Name": "Bob", "Age": 20}, {"Name": "Clark", "Age": 24}]
B = [{"Age": 17, "Class": "Economy"}, {"Age": 24, "Class": "IT"}, {"Age":17, "Class": "Arts"}]

C = []
for a in A:
    c = copy.copy(a)
    c["Class"] = []
    for b in B:
        if a["Age"]==b["Age"]:
            c["Class"].append(b["Class"])
    C.append(c)

Result is:

[{'Name': 'Alex', 'Age': 17, 'Class': ['Economy', 'Arts']},
 {'Name': 'Bob', 'Age': 20, 'Class': []},
 {'Name': 'Clark', 'Age': 24, 'Class': ['IT']}]

If it doesn't work for you, let me know :)

CodePudding user response:

I'd first turn B into a dictionary {age: [classes]}, then loop over A and combine the dictionaries – the more data you have, the more efficient it will be compared to looping over B over and over again. I'd use a collections.defaultdict for that.1

from collections import defaultdict

# {17: ['Economy', 'Arts'], 24: ['IT']}
classes_by_age = defaultdict(list)

for b in B:
    classes_by_age[b['Age']].append(b['Class']) 

With that in place, all you need to do is merge the dictionaries. I guess one of the most concise ways to do that is by passing a combination of the double asterisk operator ** and a keyword argument to the dict constructor:

merged = [dict(**a, Classes=classes_by_age[a['Age']]) for a in A]

1 If you don't want to import defaultdict, you can simply initialize classes_by_age as an empty dictionary and in the loop do:

for b in B:
    age = b['Age']
    class_ = b['Class']

    if age in classes_by_age:
        classes_by_age[age].append(class_)
    else:
        classes_by_age[age] = [class_]

But then you'd also have do adopt the final list comprehension to the one below, otherwise empty Classes would cause trouble:

[dict(**a, Classes=classes_by_age.get(a['Age'], [])) for a in A]
  • Related