简体   繁体   中英

Compare two dictionary lists, based on specific key

I'll try to be the more concise that I can.

Two dictionary lists as follows:

dictlist1 = [{'name': 'john', 'age': 30}, {'name': 'jessica', 'age': 56}, {'name': 'kirk', 'age': 20}, {'name': 'mario, 'age': 25}]

dictlist2 = [{'name': 'john', 'job': 'engineer'}, {'name': 'jessica', 'job':'nurse'}, {'name': 'mario', 'job': 'electrician'}]

My objective is to match base on the key "name" on both dictionaries and, at the end, create a third dictionary list with the key that has no match, in this case {'name':'kirk', 'age':20}, like this:

listfinal = [{'name': 'kirk', 'age': 20}]

I've tried successfully compare the equal keys, creating a new dictionary with keys that matches and adding "job" key to it, doing this:

    for dict2 in dictlist2:
        for dict1 in dictlist1:
            if dict1['name'] == dict2['name']:
                matchname1 = dict2['name']
                dictoutput = {'name': matchname1, 'age': dict1['age'], 'group': dict2['group']}
                templist.append(dictoutput)

    for dictionay in templist:
        print(dictionay)

    Output:

    {'name': 'john', 'age': '30', 'job': 'engineer'}
    {'name': 'jessica', 'age': '56', 'job': 'nurse'} 
    {'name': 'mario', 'age': '25', 'job': 'electrician'}

But absolutely no luck to get kirk user alone, not even using "else" in the inner if statement or creating a new if statement and using not equal (.=). I always get all the users when printing.

Any orientation will be highly appreciated.

Enumerate the lists and then collect the indices of matched pairs in a list inside the loop and delete corresponding elements outside the loop.

matched_d1 = []
matched_d2 = []

for j2, dict2 in enumerate(dictlist2):
    for j1, dict1 in enumerate(dictlist1):
        if dict1['name'] == dict2['name']:
            matchname1 = dict2['name']
            dictoutput = {'name': matchname1, 'age': dict1['age'], 'group': dict2['group']}
            templist.append(dictoutput) 
            matched_d1.append(j1)
            matched_d2.append(j2)
            
for j in sorted(matched_d1, reverse = True):
    dictlist1.pop(j)

for j in sorted(matched_d2, reverse = True):
    dictlist2.pop(j)

ans = dictlist1 + dictlist2

you can use set operations to get the unique name, first make a set of the names on each one and subtract both, then use that to get the appropriate item form the list

>>> name1 = set(d["name"] for d in dictlist1)
>>> name2 = set(d["name"] for d in dictlist2)
>>> name1 - name2
{'kirk'}
>>> name2 - name1
set()
>>> unique = name1 - name2
>>> listfinal = [d for n in unique for d in dictlist1 if d["name"]==n]
>>> listfinal
[{'name': 'kirk', 'age': 20}]
>>> 

Additionally, looking at @freude answers, you can make it a dictionary of name:index for each list an subtracts its keys, given that they dict.keys behave set-like in order to avoid a double loop from before to get the right item from the list

>>> name1 = {d["name"]:i for i,d in enumerate(dictlist1)}
>>> name2 = {d["name"]:i for i,d in enumerate(dictlist2)}
>>> unique = name1.keys() - name2.keys()
>>> unique
{'kirk'}
>>> [ dictlist1[name1[n]] for n in unique]
[{'name': 'kirk', 'age': 20}]
>>> 

You can use sets to find the names that are only in dictlist1 , in dictlist2 and also the common names. Then create the listfinal by keeping only the item with the name not in the common names:

dictlist1 = [{"name": "john", "age": 30}, {"name": "jessica", "age": 56}, {"name":"kirk" , "age": 20}, {"name": "mario", "age": 25}]

dictlist2 = [{"name": "john", "job": "engineer"}, {"name": "jessica", "job": "nurse"}, {"name": "mario", "job": "electrician"}]

names_dictlist1 = {item["name"] for item in dictlist1}
names_dictlist2 = {item["name"] for item in dictlist2}

common_names = names_dictlist1 & names_dictlist2

listfinal = [item for item in dictlist1 + dictlist2 if item["name"] not in common_names]

If you want one-line solution there it is

print([person for person in dictlist1 if person['name'] not in map(lambda x: x['name'], dictlist2)])

This code prints element from fist list wich "name" key doesnt occur in second list

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM