Сравните два списка словарей на основе определенного ключа

#python #list #dictionary #if-statement

#python #Список #словарь #if-оператор

Вопрос:

Я постараюсь быть как можно более кратким.

Два списка словарей следующим образом:

 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'}]
 

Моя цель — сопоставить базу по ключу «name» в обоих словарях и, в конце, создать третий список словарей с ключом, который не имеет совпадения, в данном случае {‘name’:’kirk’, ‘age’:20}, вот так:

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

Я успешно попытался сравнить равные ключи, создав новый словарь с соответствующими ключами и добавив к нему ключ «job», выполнив это:

     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'}
 

Но абсолютно не повезло получить пользователя kirk в одиночку, даже не используя «else» во внутреннем операторе if или создавая новый оператор if и используя not equal (!=). Я всегда получаю всех пользователей при печати.

Любая ориентация будет высоко оценена.

Комментарии:

1. Составьте список всех имен, которые появляются в обоих (что вы почти сделали); тогда любые имена, отсутствующие в этом списке, — это те, которые вам нужны.

2. Ваши определения dictlist1 и dictlist2 недопустимы для Python.

3. Спасибо, @ScottHunter. Я внесу соответствующие исправления! Это было использовано в качестве примера, но я понимаю суть.

Ответ №1:

Перечислите списки, а затем соберите индексы совпадающих пар в списке внутри цикла и удалите соответствующие элементы вне цикла.

 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
 

Комментарии:

1. Большое спасибо, @freude! Это было идеально для понимания индекса списка, в котором находится «другой» словарь.

Ответ №2:

Вы можете использовать sets для поиска имен, которые есть только в dictlist1 , в dictlist2 , а также общих имен. Затем создайте listfinal , сохранив только элемент с name не в общих именах:

 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 amp; names_dictlist2

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

Комментарии:

1. БОЖЕ … это сделало трюк.! Очень признателен! Я так много раз пробовал цикл, что забыл о реальной проблеме… Я полностью отбросил логику, стоящую за последней строкой!

Ответ №3:

Если вам нужно однострочное решение, оно есть

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

Этот код выводит элемент из первого списка, ключ «name» которого не встречается во втором списке

Комментарии:

1. Еще одна отличная строка, которая позволяет этому работать! Это так просто и аккуратно. Спасибо!

Ответ №4:

вы можете использовать операции набора для получения уникального имени, сначала создайте набор имен для каждого из них и вычтите оба, затем используйте это, чтобы получить соответствующий элемент из списка

 >>> 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}]
>>> 
 

Кроме того, глядя на ответы @freude, вы можете сделать его словарем name:index для каждого списка, который вычитает его ключи, учитывая, что они dict.keys ведут себя как набор, чтобы избежать двойного цикла, предшествующего получению нужного элемента из списка

 >>> 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}]
>>> 
 

Комментарии:

1. Это не приведет к перехвату «совпадающих» имен dictlist2 .

2. @ScottHunter просто сделайте то же самое для другого случая, просто поменяйте местами роль dictlist1 и dictlist2

3. Еще один способ сделать это. Спасибо @Cooperfield! Учусь у всех вас, ребята.