#python
#python
Вопрос:
Допустим, у меня есть следующие списки словарей с одинаковым идентификатором атрибута. Я хочу знать, какой самый быстрый и правильный способ объединить их в соответствии со значением идентификатора.
perperson = [
{'id':1, 'firstName':'test','lastName':'testlast'},
{'id':2, 'firstName':'test2','lastName':'testlast2'},
{'id':3, 'firstName':'test3','lastName':'last3'},
]
peremail = [
{'id':1, 'email':'test@test'},
{'id':2, 'email':'test2@test2'},
{'id':3, 'email':'test3@test3'},
]
Результат
comdined= [
{'id':1, 'firstName':'test','lastName':'testlast','email':'test@test'},
{'id':2, 'firstName':'test2','lastName':'testlast2','email':'test2@test2'},
{'id':3, 'firstName':'test3','lastName':'last3','email':'test3@test3'},
]
Комментарии:
1.
comdined= [{**x, **y} for x,y in zip(perperson, peremail)]
2. Списки уже отсортированы по идентификатору? Существует ли один и тот же набор идентификаторов в обоих списках?
3. Преобразуйте свой список в список dicts по идентификаторам… Звучит более уместно
4. В вашем названии говорится более быстрый способ — быстрее, чем что? Вы не показали свой текущий код (если он есть …)
Ответ №1:
Преобразуйте один из списка в dict, а затем выполните поиск
Пример:
perperson = [
{'id':1, 'firstName':'test','lastName':'testlast'},
{'id':2, 'firstName':'test2','lastName':'testlast2'},
{'id':3, 'firstName':'test3','lastName':'last3'},
]
peremail = [
{'id':1, 'email':'test@test'},
{'id':2, 'email':'test2@test2'},
{'id':3, 'email':'test3@test3'},
]
peremail_t = {i.pop('id'): i for i in peremail} # Easy look-up
comdined = [{**i, **peremail_t[i['id']]} for i in perperson]
print(comdined)
Вывод:
[{'email': 'test@test', 'firstName': 'test', 'id': 1, 'lastName': 'testlast'},
{'email': 'test2@test2',
'firstName': 'test2',
'id': 2,
'lastName': 'testlast2'},
{'email': 'test3@test3', 'firstName': 'test3', 'id': 3, 'lastName': 'last3'}]
ИЛИ обновить на месте
Пример:
for i in perperson:
i.update(peremail_t[i['id']])
Ответ №2:
Если вы имеете дело с большими объемами табличных данных в списках словарей, рассмотрите возможность использования фрейма данных Pandas. Объединение фреймов данных по идентификатору очень простое, оно будет быстрее, если таблицы будут большими, и это дает вам больше возможностей для решения потенциальных проблем, таких как несоответствие идентификаторов.
import pandas as pd
merged = pd.DataFrame(perperson).merge(pd.DataFrame(peremail), on="id")
Вы можете использовать merged.to_dict("records")
, если вам нужно преобразовать его обратно в словари.
Если вы не хотите использовать pandas, вот генератор, который может объединять произвольное количество списков словарей, которые могут быть не отсортированы и могут иметь несовпадающие идентификаторы (что эквивалентно «внешнему» слиянию в pandas). Это, вероятно, будет медленнее, чем преобразование списков в словари, но максимально эффективно с использованием списков.
def join_by_key(key, *lists):
lists = [sorted(L, key=lambda d: d[key]) for L in lists]
while lists:
min_key = min(L[0][key] for L in lists)
r = {}
for L in lists:
if L[0][key] == min_key:
r.update(L.pop(0))
yield r
lists = [L for L in lists if L]
print(list(join_by_key("id", perperson, peremail)))
Ответ №3:
вот мое предложение простого цикла:
perperson = [{'id':1, 'firstName':'test','lastName':'testlast'},
{'id':2, 'firstName':'test2','lastName':'testlast2'},
{'id':3, 'firstName':'test3','lastName':'last3'},
]
peremail = [
{'id':1, 'email':'test@test'},
{'id':2, 'email':'test2@test2'},
{'id':3, 'email':'test3@test3'},
]
for n,j in zip(perperson,peremail):
n['email']=j['email']
print(perperson)
ее вывод
[{'lastName': 'testlast', 'id': 1, 'firstName': 'test', 'email': 'test@test'}, {'lastName': 'testlast2', 'id': 2, 'firstName': 'test2', 'email': 'test2@test2'}, {'lastName': 'last3', 'id': 3, 'firstName': 'test3', 'email': 'test3@test3'}]
Ответ №4:
Учитывая, что все словари имеют ключ «id», а списки упорядочены по значениям «id»:
def combine_dicts(dict_1, dict_2):
if dict_1['id'] == dict_2['id']:
for k in dict_2:
if k in dict_1:
continue
else:
dict_1.update({k:dict_2[k]})
return dict_1
for dict1, dict2 in zip(perperson, peremail):
combine_dicts(dict1, dict2)