Лучший способ, которым я могу описать то, что я хотел бы достичь, - это обратиться к тому, как работает функция SQL INNER JOIN
для отображения данных из двух таблиц, определяемых соответствующим именем столбца.
Я хотел бы получить аналогичную функцию, хотя, используя Python (предпочтительно 3.x), и вместо таблиц с соответствующим именем столбца я хотел бы объединить все два словаря вместе на основе сопоставления {k: v}.
Например...
lst_1 = [
{
'City' : 'Boston',
'State' : 'Massechusets',
'Name' : 'Kim Tuttles',
'Country' : 'United State'
},
{
'City' : 'Portland',
'Name' : 'Larry Bird',
'State' : 'Oregon'
},
{
'City' : 'Chicago',
'Name' : 'John Jacobs',
'State' : 'Illinois'
}
]
lst_2 = [
{
'Hobby' : 'Tennis',
'Build' : 'Athletic',
'Height' : 'Six Feet, One Inch',
'Name' : 'Kim Tuttles',
'Birthplace': 'Italy'
},
{
'Name' : 'John Jacobs',
'Hobby' : 'Baseball',
'Build' : 'Muscular',
'Height' : 'Five Feet, Eight Inches'
}
]
Я хотел бы найти способ объединить словари из каждого списка, но только там, где найдена соответствующая пара {Key: Value}. Результат будет выглядеть так...
merged_lst = [
{
'Hobby' : 'Tennis',
'Build' : 'Athletic',
'Height' : 'Six Feet, One Inch',
'Birthplace': 'Italy'
'City' : 'Boston',
'State' : 'Massechusets',
'Name' : 'Kim Tuttles', # Merge on matching name
'Country' : 'United State'
},
{
'Name' : 'John Jacobs', # Merge on matching name
'Hobby' : 'Baseball',
'Build' : 'Muscular',
'Height' : 'Five Feet, Eight Inches'
'City' : 'Chicago',
'State' : 'Illinois'
}
]
Мне удалось найти способ слияния словарей с использованием dict.update
и zip()
, хотя это было только при работе с двумя независимыми словарями, и это все еще было не совсем правильно. Я ценю любые советы и благодарю вас заранее.
В Python 3. 5+ мы можем уйти со следующим, игнорируя проблемы из дополнительных столкновений ключей.
k = 'Name'
merged_lst = [{**a, **b} for a in lst_1 for b in lst_2 if a[k]==b[k]]
{**a, **b}
- это аккуратный способ распаковать два словаря, которые рассматриваются в комбинированном словаре (я считаю, что при столкновении он использует значение из b
вместо a
). Это единственный шаг, который требует 3. 5+. В Python 2.x со строковыми клавишами аналогичная конструкция - dict(a, **b)
, хотя Гвидо нахмурился. Другие варианты более подробные.lst_1
и lst_2
, используя for
два раза.'Name'
, поэтому бит a[k]==b[k]
.lst_1
или lst_2
, подходы, связанные с dict.update()
, скорее всего, быстрее. Они могут быть в любом случае, хотя синтаксис не так хорош, я не думаю.O(m*n)
во вложенном понимании, когда для рассматриваемой задачи O(m+n)
возможна.
O(m+n)
? Это средний случай? В моей работе с нулями лучшее решение, которое я нашел, - O(m*log(m)+n*log(n))
худшем случае. Какой алгоритм лучше использовать для сложности времени здесь?
вы можете сделать что-то вроде этого:
for l2 in lst_2:
l2.update(next(l1 for l1 in lst_1 if l1["Name"] == l2["Name"]))
Это похоже на левое объединение в RDMS, например MySQL, и функцию $ lookup (aggregation) MongoDB. Вы можете изучить их для дальнейшего уточнения.
Одним из способов я сделал это:
Сначала создаются два словаря из списков с использованием имени в качестве ключа
lst1_dict={lst_1[i]["Name"]: lst_1[i] for i in range(len(lst_1))}
lst2_dict={lst_2[i]["Name"]: lst_2[i] for i in range(len(lst_2))}
{ 'John Jacobs': { 'City': 'Chicago',
'Name': 'John Jacobs',
'State': 'Illinois'},
'Kim Tuttles': { 'City': 'Boston',
'Country': 'United State',
'Name': 'Kim Tuttles',
'State': 'Massechusets'},
'Larry Bird': { 'City': 'Portland',
'Name': 'Larry Bird',
'State': 'Oregon'}
}
{
'John Jacobs': { 'Build': 'Muscular',
'Height': 'Five Feet, Eight Inches',
'Hobby': 'Baseball',
'Name': 'John Jacobs'},
'Kim Tuttles': { 'Birthplace': 'Italy',
'Build': 'Athletic',
'Height': 'Six Feett, One Inch',
'Hobby': 'Tennis',
'Name': 'Kim Tuttles'}
}
Получили общие имена в обоих
common_names=list(set(lst1_dict.keys())&set(lst2_dict.keys()))
Итерации по общим именам и их объединение
merged_list=[]
for name in common_names:
lst1_val=lst1_dict[name] #value from lst1 dictionary
lst2_val=lst2_dict[name] #value from lst2 dictionary
#MERGE
new_dict={}
new_dict[name] = lst1_val.copy()
new_dict[name].update(lst2_val)
merged_list.append(new_dict[name])
[ { 'Birthplace': 'Italy',
'Build': 'Athletic',
'City': 'Boston',
'Country': 'United State',
'Height': 'Six Feett, One Inch',
'Hobby': 'Tennis',
'Name': 'Kim Tuttles',
'State': 'Massechusets'},
{ 'Build': 'Muscular',
'City': 'Chicago',
'Height': 'Five Feet, Eight Inches',
'Hobby': 'Baseball',
'Name': 'John Jacobs',
'State': 'Illinois'}]
Вы можете создать функцию для фильтрации одного списка для дубликатов имен, переноса данных в список результатов и их обновления:
Функция:
def mergeSameNameDicts(l1,l2):
duplicateNames = set ( p["Name"] for p in l1) & set( p["Name"] for p in l2)
import copy
rv = [] # collects enriched dicts
for d in l1:
if d["Name"] in duplicateNames:
rv.append(copy.copy(d)) # copy dict over from l1
for d in l2: # enhance with data from l2
if (d["Name"] in duplicateNames): # if name is a dupe. enhence all
for d1 in rv: # dicts with that name inside rv
if (d["Name"] == d1["Name"]): # the values of v2 will overwrite l1 if keys
d1.update(d) # present in dicts of l1 and l2
return rv
print(mergeSameNameDicts(lst_1,lst_2))
Выход:
[{'City': 'Boston',
'State': 'Massechusets',
'Name': 'Kim Tuttles',
'Country': 'United State',
'Hobby': 'Tennis',
'Build': 'Athletic',
'Height': 'Six Feett, One Inch',
'Birthplace': 'Italy'},
{'City': 'Chicago',
'Name': 'John Jacobs',
'State': 'Illinois',
'Hobby': 'Baseball',
'Build': 'Muscular',
'Height': 'Five Feet, Eight Inches'}]
set
в строке № 3? Я еще не знаком с этой функцией.
'Name'
здесь) заранее?'Name'
как вы упомянули.