2013-05-07 3 views
1

У меня есть ДИКТ так:питон вложенными ДИКТ понимание с кортежем как ключевой

{ ('name', 'user1'): 'foo', 
    ('user', 'user1'): 'bar', 
    ('name', 'user2'): 'bat', 
    ('user', 'user2'): 'baz' } 

, и я хотел бы преобразовать в:

{ 'user1': {'name': 'foo', 'user': 'bar'}, 
    'user2': {'name': 'bat', 'user': 'baz'} } 

Я могу сделать это с Словаре по умолчанию легко, но я хотел бы использовать понимание dict.

До сих пор у меня есть:

{user: {key:value for (key, user), value in my_dict.items()}} 

Но пользователь не внутри цикла, так что я name 'user' is not defined ошибка.

Как я могу достичь этого с помощью понятий dict?

+0

Я не думаю, что это можно сделать красиво в понимании, даже с гнездом. Проблема в том, что вы хотите агрегировать результаты из нескольких элементов, что требует эффекта типа «zip». – Antimony

+0

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

+0

Вы можете сделать это с пониманием dict, но вам придется предварительно сгруппировать значения, которые будут игнорировать точку. –

ответ

3

Можно использовать определение dict, если оба ключа и значение имеют прямую связь «один на один» с элементами в последовательности.

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

Группировка, безусловно, возможна с itertools.groupby(), но это потребует сортировки, что делает ее менее эффективной по сравнению с решением defaultdict plus loop.

Использование itertools.groupby:

from itertools import groupby 

user = lambda item: item[0][1] 

{user: {key[0]: value for key, value in grouped} 
    for user, grouped in groupby(sorted(my_dict.items(), key=user), key=user)} 

Выход демо:

>>> {user: {key[0]: value for key, value in grouped} 
...  for user, grouped in groupby(sorted(my_dict.items(), key=user), key=user)} 
{'user2': {'name': 'bat', 'user': 'baz'}, 'user1': {'name': 'foo', 'user': 'bar'}} 

Это О (п войти п) решение, по сравнению с О (п) сложности defaultdict раствора:

from collections import defaultdict 

output = defaultdict(dict) 

for (key, user), value in my_dict.iteritems(): 
    output[user][key] = value 
0

это нормально работает:

from __future__ import print_function 
from itertools import groupby 
from operator import itemgetter 

d=dict({('name', 'user1'): 'foo', ('user', 'user1'): 'bar', 
     ('name', 'user2'): 'bat', 
     ('user', 'user2'): 'baz' }) 

l = [] 
for key, val in d.items() : 
    l.append([key[1], key[0], val]) 

l.sort(key=itemgetter(0)) 

d_ = dict() 
for key, group in groupby(l, lambda x: x[0]): 
    dic = dict() 
    for thing in group: 
     dic[thing[1]] = thing[2] 
    d_[key] = dic 

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

+0

Почему вы импортировали print_function? – rikAtee

+0

Я с python 3.0. print, если он импортирован из будущего, является методом – octoback

+1

, но вы не используете печать в своем коде – rikAtee

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