2016-02-15 6 views
0

Я, вероятно, не использую здесь правильные слова, но в основном я хочу добавить еще один ключ рядом с первым предоставленным ключом.Python defaultdict - добавить еще один ключ?

Это то, что я в настоящее время:

def transform_result(self, data): 
    type_map = defaultdict(list) 
    for entry in data: 
     type_map[entry['type']].append({ 
      'id': entry['id'], 
      'tag': entry['tag'], 
     }) 
    ret = [] 
    for key, value, in type_map.items(): 
     ret.append({ 
      'type': key, 
      'tags': value, 
     }) 
    return ret 

Вход:

[ 
    OrderedDict([ 
     ('id', 1), 
     ('type', 'Color'), 
     ('writable', True), 
     ('tag', 'Blue') 
    ]), 
    OrderedDict([ 
     ('id', 2), 
     ('type', 'Color'), 
     ('writable', True), 
     ('tag', 'Red') 
    ]), 
    OrderedDict([ 
     ('id', 3), 
     ('type', 'Color'), 
     ('writable', True), 
     ('tag', 'Green') 
    ]), 
    OrderedDict([ 
     ('id', 4), 
     ('type', 'Shape'), 
     ('writable', False), 
     ('tag', 'Square') 
    ]), 
    OrderedDict([ 
     ('id', 5), 
     ('type', 'Shape'), 
     ('writable', False), 
     ('tag', 'Circle') 
    ]) 
] 

Желаемый результат:

[ 
    { 
     'type': 'Color', 
     'writable': True, 
     'tags': [ 
      { 
       'tag': 'Blue', 
       'id': 1 
      }, 
      { 
       'tag': 'Red', 
       'id': 2 
      }, 
      { 
       'tag': 'Green', 
       'id': 3 
      } 
     ] 
    }, 
    { 
     'type': 'Shape', 
     'writable': False, 
     'tags': [ 
      { 
       'tag': 'Square', 
       'id': 4 
      }, 
      { 
       'tag': 'Circle', 
       'id': 5 
      }, 

     ] 
    }, 
] 

Как это должно быть достигнуто?


Редактировать: Я получил его, извините, я полностью резиновый уклонил это. Вот мое Hacky решение:

def transform_result(self, data): 
    type_map = defaultdict(list) 
    for entry in data: 
     type_map[entry['type'], entry['many']].append({ 
      'id': entry['id'], 
      'tag': entry['tag'], 
     }) 
    ret = [] 
    for key, value, in type_map.items(): 
     ret.append({ 
      'type': key[0], 
      'many': key[1], 
      'tags': value 
     }) 
    return ret 

В принципе, то, что вводит в заблуждение меня было то, как получить доступ к many после того, как первый цикл был завершен. Мое решение состояло в том, чтобы быстро положить type и many вместе в небольшом списке, затем получить к ним доступ с [0] и [1], он работает!

+2

Вы можете указать более точное описание вашей цели вместо [XYproblem] (http://xyproblem.info/)? вход и выход, [MCVE] (http://stackoverflow.com/help/mcve) – Pynchia

+0

ОК, работающий над ним – dtgq

+0

'defaultdict' построен вокруг добавления значения для одного отсутствующего ключа; если вы хотите что-то еще, вы можете также начать с 'class MyThing (dict)'. – jonrsharpe

ответ

1

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

def transform_result(self, data): 
    type_map = defaultdict(list) 
    for entry in data: 
     type_map[entry['type'], entry['writable']].append({ 
      'id': entry['id'], 
      'tag': entry['tag'], 
     }) 
    ret = [] 
    for (k_type, k_writable), value in type_map.items(): 
     ret.append({ 
      'type': k_type, 
      'writable': k_writable, 
      'tags': value, 
     }) 
    return ret 
+0

Я предпочитаю ваше решение, похоже, наиболее похоже на то, что я хочу достичь. Я не знал, что переменные можно назначить вложенным таким образом, довольно аккуратно! Благодарю. – dtgq

1

Вот предложение, обратите внимание, что это решение n * lg (n), вы можете решить проблему в n, но если у вас нет очень больших наборов данных, это не имеет значения. Используйте его в качестве вдохновения;)

from collections import OrderedDict 
from itertools import groupby 
from operator import itemgetter 
from pprint import pprint 


foo = [ 
    OrderedDict([ 
     ('id', 1), 
     ('type', 'Color'), 
     ('writable', True), 
     ('tag', 'Blue') 
    ]), 
    ... 
    ... 
    ... 
    OrderedDict([ 
     ('id', 5), 
     ('type', 'Shape'), 
     ('writable', False), 
     ('tag', 'Circle') 
    ]) 
] 


def transform_result(data): 
    key_func = itemgetter('type') 
    for g, items in groupby(sorted(foo, key=key_func), key=key_func): 
     item = {'type': g, 'tags': []} 
     for i in items: 
      item['writeable'] = i['writable'] 
      item['tags'].append({'tag': i['tag'], 'id': i['id']}) 
     yield item 

pprint(list(transform_result(foo))) 

Выход

[{'tags': [{'id': 1, 'tag': 'Blue'}, 
      {'id': 2, 'tag': 'Red'}, 
      {'id': 3, 'tag': 'Green'}], 
    'type': 'Color', 
    'writeable': True}, 
{'tags': [{'id': 4, 'tag': 'Square'}, {'id': 5, 'tag': 'Circle'}], 
    'type': 'Shape', 
    'writeable': False}] 
+0

Если набор данных не очень большой, использование подхода генератора кажется излишним, не так ли? И вместо того, чтобы обновлять 'item ['writeable']' на каждой итерации, вы можете переместить это назначение вне внутреннего цикла. Если вы сделаете это до 'yield', вы будете иметь такое же поведение, если вы переместите его перед внутренним циклом, вы учтете первый элемент, а не последний. Обратите внимание, что любое из этих действий * не * желательно, согласно комментариям (в исходном ответе нет информации). – MariusSiuram