2015-11-11 5 views
-1

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

{'name': Fido, 'breed': Dalmatian, 'age': 3} 
{'name': Rex, 'breed': Dalmatian, 'age': 2} 
{'name': Max, 'breed': Dalmatian, 'age': 0} 
{'name': Rocky, 'breed': Pitbull, 'age': 6} 
{'name': Buster, 'breed': Pitbull, 'age': 7} 

Даст мне:

Dalmation: {'name': [Fido, Rex, Max], 'age': [3, 2, 0]} 
Pitbull : {'name': [Rocky, Buster], 'age': [6, 7]} 

Я пытался найти элегантное и вещее решение этой проблемы не дали никаких результатов.

+1

Итак, что вы пробовали? Можете ли вы дать нам свой код? –

+0

Как входные данные являются вложенными словарями? Также почему бы не показать нам свое неудобное/непсиховое решение, чтобы мы могли предложить улучшения, а также знаем, что вы хотя бы приложили определенные усилия для решения вашей проблемы. –

ответ

1
doglist = [ 
    {'name': 'Fido', 'breed': 'Dalmatian', 'age': 3}, 
    {'name': 'Rex', 'breed': 'Dalmatian', 'age': 2}, 
    {'name': 'Max', 'breed': 'Dalmatian', 'age': 0}, 
    {'name': 'Rocky', 'breed': 'Pitbull', 'age': 6}, 
    {'name': 'Buster', 'breed': 'Pitbull', 'age': 7}, 
] 
dogdict = {} 

for dog in doglist: 
    if dog['breed'] in dogdict: 
     dogdict[dog['breed']]['name'].append(dog['name']) 
     dogdict[dog['breed']]['age'].append(dog['age']) 
    else: 
     dogdict[dog['breed']] = {'name': [dog['name']], 'age': [dog['age']]} 
4

Здесь возможны два варианта:

Пример # 1: http://ideone.com/RRzWaL

dogs = [ 
    {'name': 'Fido', 'breed': 'Dalmatian', 'age': 3}, 
    {'name': 'Rex', 'breed': 'Dalmatian', 'age': 2}, 
    {'name': 'Max', 'breed': 'Dalmatian', 'age': 0}, 
    {'name': 'Rocky', 'breed': 'Pitbull', 'age': 6}, 
    {'name': 'Buster', 'breed': 'Pitbull', 'age': 7}, 
] 

# get rid of duplicates 
breeds = set([ dog['breed'] for dog in dogs ]) 

breed_dict = {} 
for breed in breeds: 
    # get the names of all dogs corresponding to `breed` 
    names = [ dog['name'] for dog in dogs if dog['breed'] == breed ] 

    # get the ages of all dogs corresponding to `breed` 
    ages = [ dog['age'] for dog in dogs if dog['breed'] == breed ] 

    # add to the new dict 
    breed_dict[breed] = { 'age': ages, 'name': names } 

Я также добавить упрощение @ кода JohnGordon, используя collections «s defaultdict:

Пример № 2: http://ideone.com/B2xLGR

from collections import defaultdict 

doglist = [ 
    {'name': 'Fido', 'breed': 'Dalmatian', 'age': 3}, 
    {'name': 'Rex', 'breed': 'Dalmatian', 'age': 2}, 
    {'name': 'Max', 'breed': 'Dalmatian', 'age': 0}, 
    {'name': 'Rocky', 'breed': 'Pitbull', 'age': 6}, 
    {'name': 'Buster', 'breed': 'Pitbull', 'age': 7}, 
] 
dogdict = defaultdict(lambda: defaultdict(list)) 

for dog in doglist: 
    # `defaultdict` allows us to not have to check whether 
    # a key is already in the `dict`, it'll just set it to 
    # a default (`[]` in the inner dict in our case) 
    # if it's not there, and then append it. 
    dogdict[dog['breed']]['name'].append(dog['name']) 
    dogdict[dog['breed']]['age'].append(dog['age']) 

Обратите внимание, что второй пример с использованием defaultdict будет быстрее первого примера, который имеет два отдельных понимания списка (т. Е. Две отдельные внутренние петли).

0

Используйте itertools.groupby, чтобы отделить словари, а затем построить новые словари.

import itertools, collections, operator 
dees = [{'name': 'Fido', 'breed': 'Dalmatian', 'age': 3}, 
     {'name': 'Rex', 'breed': 'Dalmatian', 'age': 2}, 
     {'name': 'Max', 'breed': 'Dalmatian', 'age': 0}, 
     {'name': 'Rocky', 'breed': 'Pitbull', 'age': 6}, 
     {'name': 'Buster', 'breed': 'Pitbull', 'age': 7}] 

breed = operator.itemgetter('breed') 
filtr = ['name', 'age'] 
new_dees = [] 
for key, group in itertools.groupby(dees, breed): 
    d = collections.defaultdict(list) 
    for thing in group: 
     for k, v in thing.items(): 
      if k in filtr: 
       d[k].append(v) 
    new_dees.append({key:d}) 

В качестве альтернативы вы можете просто извлечь значения, которые вместо того, чтобы использовать if k in filtr. Я не решил, какой альтернативе мне больше нравится, поэтому я тоже опубликую это.

# using previously defined functions and variables 
items_of_interest = operator.itemgetter(*filtr) 
for key, group in itertools.groupby(dees, breed): 
    d = collections.defaultdict(list) 
    for thing in group: 
     values = items_of_interest(thing) 
     for k, v in zip(filtr, values): 
      d[k].append(v) 
    new_dees.append({key:d}) 
Смежные вопросы