2016-02-03 2 views
1

У меня есть список словарей, в которых некоторые значения являются строками, а остальные значения являются целыми числами:Создание нового словаря из списка словарей в Python

list_countries = [{'country' : 'Suriname', 
      'population' : 532724, 
      'capital': 'Paramaribo', 
      'anthem': 'God zij met ons Suriname'}, 
      {'country' : 'Sweden', 
      'population' : 9683248, 
      'capital': 'Stockholm', 
      'anthem': 'Du gamla, Du fria'}, 
      ...] 

Я хотел бы изменить каждый из них кнопочная пары значений в один большой новый словарь. Тем не менее, мой подход имеет проблемы:

dict_countries = { 'countries':  [], 
        'pop':    [], 
        'capital_city': [], 
        'national_anthem': [] } 

Я тогда перебирать и добавить все значения с .extend().

for dictionary in list_countries: 
    dict_countries['countries'].extend(dictionary['country']) 
    dict_countries['pop'].extend(dictionary['population']) 
    dict_countries['capital_city'].extend(dictionary['capital']) 
    dict_countries['national_anthem'].extend(dictionary['anthem']) 

Однако это не работает. Все строки разбиты по буквам. Для целых чисел я получаю ошибку:

TypeError: 'int' object is not iterable 

Каков правильный подход?

EDIT: Я считаю, что есть значение для каждой клавиши. Однако, скажем так, нет. Как бы я мог переписать выше, чтобы добавить NaN, если не найдено никакого значения.

+0

Рассмотрим, если вы _really_ хотите сделать это. Ваш список списков немного хрупкий: если какой-либо из списков выходит из строя, все это становится беспорядком. Альтернативой является диктофон dicts, индексированный по стране. –

+0

@ PM2Ring Я собираюсь импортировать этот словарь в pandas DataFrame. Возможно, я снова задам вопрос, как это сделать. – EB2127

ответ

3

.extend() ожидает, что аргумент, переданный ему, будет итерируемым, т.е. список или строку и т. д. В соответствии с вашим примером, population является целым числом и, следовательно, не является итерабельным, следовательно, ваше сообщение об исключении.

Если вы измените его на .append(), он будет вести себя так, как вы ожидаете.

0

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

list_countries = [{'country' : 'Suriname', 
      'population' : 532724, 
      'capital': 'Paramaribo', 
      'anthem': 'God zij met ons Suriname'}, 
      {'country' : 'Sweden', 
      'population' : 9683248, 
      'capital': 'Stockholm', 
      'anthem': 'Du gamla, Du fria'}, 
      ] 


from collections import defaultdict 
d = defaultdict(list) 
for i in list_countries: 
    for k,v in i.items(): 
    d[k].append(v) 

The d может быть coverted обратно в обычный dict легко.

1

Причина, по которой вы получаете выход, заключается в том, что существует разница между append и extend по списку. Если вы extend с итерируемым как параметр (который является строкой), он будет вставлять каждый элемент итерабельного в dict (который является каждой буквой для строки). Однако он не подходит для int, поскольку это не является итерируемым. Я бы предпочел использовать append, который просто добавляется к списку в dict.

list_countries = [{'country' : 'Suriname', 
      'population' : 532724, 
      'capital': 'Paramaribo', 
      'anthem': 'God zij met ons Suriname'}, 
      {'country' : 'Sweden', 
      'population' : 9683248, 
      'capital': 'Stockholm', 
      'anthem': 'Du gamla, Du fria'}] 

dict_countries = { 'countries':  [], 
        'pop':    [], 
        'capital_city': [], 
        'national_anthem': [] } 

for dictionary in list_countries: 
    dict_countries['countries'].append(dictionary['country']) 
    dict_countries['pop'].append(dictionary['population']) 
    dict_countries['capital_city'].append(dictionary['capital']) 
    dict_countries['national_anthem'].append(dictionary['anthem']) 

print dict_countries 
1

У вас есть две проблем решить здесь:
создавать списки значений из ваших словарей и перевести старые ключи к их новым именам.

Использовать метод встроенного словаря setdefault и использовать переводческий словарь как словарь в буквальном смысле (то есть для перевода).

Установите переводы, как это:

>>> translations = {'country': 'countries', 
...     'population': 'pop', 
...     'capital': 'capital_city', 
...     'anthem': 'national_anthem'} 

Затем построить свой новый словарь:

>>> merged = {} 
>>> for d in list_countries: 
...  for k in d: 
...   key = translations.get(k, k) 
...   merged.setdefault(key, []).append(d[k]) 
... 
>>> merged 
{'national_anthem': ['God zij met ons Suriname', 'Du gamla, Du fria'], 'capital_city': ['Paramaribo', 'Stockholm'], 'pop': [532724, 9683248], 'countries': ['Suriname', 'Sweden']} 

...и если вы можете быть уверены, что все словари разделяют одни и те же ключи, вот Oneliner:

>>> {translations.get(k,k):[d[k] for d in list_countries] for k in list_countries[0].keys()} 
{'national_anthem': ['God zij met ons Suriname', 'Du gamla, Du fria'], 'capital_city': ['Paramaribo', 'Stockholm'], 'pop': [532724, 9683248], 'countries': ['Suriname', 'Sweden']} 
+0

Вы можете использовать 'collections.defaultdict', чтобы избежать« setdefault »(я нахожу его немного чище). В противном случае, хороший подход. +1 – MariusSiuram

0
keys = list_countries[0].keys() 
values = (list(t) for t in zip(*[d.values() for d in list_countries])) 
dict(zip(keys, values)) 
+0

У вас нет гарантии, что словарь вернет значения с тем же шаблоном. Это то, что происходит с типичной реализацией, да, но это не гарантия от dict. Таким образом, ваш подход может давать такие вещи, как «страна»: [«Суринам», 12345, «Франция», «Берлин»]. – MariusSiuram

+0

Документация на Python гласит: Если элементы(), keys(), values ​​(), iteritems(), iterkeys() и itervalues ​​() вызываются без промежуточных изменений в словаре, списки будут непосредственно соответствовать. Это позволяет создавать пары (значение, ключ), используя zip(): pairs = zip (d.values ​​(), d.keys()). (https://docs.python.org/2/library/stdtypes.html#dict.items) – hayordi

+0

Да. В ** тот же ** словарь. Вы используете его для нескольких словарей. Насколько мне известно, для этого нет никаких гарантий. – MariusSiuram

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