2016-11-27 7 views
3

У меня есть три словаря:Объединение словарей в словарь списков

dict1 = {'a': 1, 'b': 2, 'c': 3} 
dict2 = {'b': 3, 'c': 4} 
dict3 = {'c': 4, 'd': 4} 

Я хочу «слияние» их в словарь списков

merged_dict = {'a':[1, np.nan, np.nan], 
       'b':[2, 3, np.nan], 
       'c':[3, 4, 4], 
       'd':[np.nan, np.nan, 4]} 

Есть ключи, которые в некоторых словарях и не другие, которые делают это своего рода болью к петле, хотя. Интересно, что самый чистый способ сделать это.

+0

Почему 4 ключа d приходят после других элементов в списке? – PeteyPii

+1

, потому что он не существует в первых двух словарях – Chris

+0

Думаю, вы просто укусили пулю и перебрали словари и ключи. У вас может быть только итерация, чтобы собрать все ключи. – hpaulj

ответ

5

Как уже упоминался в комментариях, которые необходимо перебрать все словари первого, чтобы собрать все ключи, в противном случае нет никакого способа узнать, какие ключи отсутствуют каждый отдельный Dict. Затем вы можете построить merged_dict с пониманием dict.

import numpy as np 

dict1 = {'a': 1, 'b': 2, 'c': 3} 
dict2 = {'b': 3, 'c': 4} 
dict3 = {'c': 4, 'd': 4} 

all_dicts = (dict1, dict2, dict3) 

keys = {k for d in all_dicts for k in d} 
merged_dict = {k: [d.get(k, np.nan) for d in all_dicts] for k in keys} 
print(merged_dict) 

выход

{'a': [1, nan, nan], 'b': [2, 3, nan], 'c': [3, 4, 4], 'd': [nan, nan, 4]} 

Вы могли поставить множество понимание внутри Dict понимания, но я думаю, что делает код труднее читать.

merged_dict = {k: [d.get(k, np.nan) for d in all_dicts] 
    for k in {k for d in all_dicts for k in d}} 

На самом деле, что двойные for петли в множестве комп не столь эффективным. Это, вероятно, не имеет большого значения для малых dicts, но если dicts велики, что было бы более эффективным, чтобы сделать одну из этих петель при скорости С помощью set.update метода:

keys = set() 
for d in all_dicts: 
    keys.update(d.keys()) 

Это, вероятно, еще лучше:

keys = set().union(*all_dicts) 

Thanks, Dan. D за это предложение!

Вот еще один способ, с помощью itertools:

from itertools import chain 
keys = set(chain.from_iterable(dicts)) 
+2

Даже 'keys = set(). Union (* all_dicts)'. –

+0

@DanD. Хорошая точка зрения! Я удивлен, что сам не думал об этом. :) Теперь я испытываю соблазн написать тест «timeit», чтобы сравнить все эти варианты, в том числе Brendan's ... –

2

Это должно быть сделано.

from itertools import chain 

dicts = [dict1, dict2, dict3] 
keys = set(chain(*[d.keys() for d in dicts])) 
merged_dict = {k: [d.get(k, np.nan) for d in dicts] for k in keys} 
+0

Это в основном то же самое, что и ответ выше и 100% правильный, но немного меньше объяснений, поэтому я собираюсь с ним, но я проголосовал за это, так как это правильно. – Chris

3

pandas делает хорошую работу при разборе словарей и их объединения. Вы можете сделать что-то подобное.

установка

import pandas as pd 

dict1 = {'a': 1, 'b': 2, 'c': 3} 
dict2 = {'b': 3, 'c': 4} 
dict3 = {'c': 4, 'd': 4} 

решение

df = pd.concat([pd.Series(d) for d in [dict1, dict2, dict3]], axis=1) 
df 

enter image description here

Чтобы получить словарь, который вы ищете.

df.T.to_dict('list') 

{'a': [1.0, nan, nan], 
'b': [2.0, 3.0, nan], 
'c': [3.0, 4.0, 4.0], 
'd': [nan, nan, 4.0]} 
+0

Я действительно набрал это и пошел с этим маршрутом, потому что я все равно конвертировал в Pandas DataFrame конец, и это было легче читать для меня. Я бы поспорил, что другой ответ будет быстрее, поэтому я оставлю это в качестве выбранного ответа, если это не ускорится, но этот код стал легче читать для меня. – Chris

+0

@ Крис. Другой ответ быстрее. Но я согласен, это более интуитивно. – piRSquared

+0

Я не согласен с выбором. Если в итоге у меня получится больше голосов, в конце я изменю свой выбор. – Chris

Смежные вопросы