Forma Pythonic para revertir diccionarios nesteds

Tengo un diccionario nested de personas y valoraciones de artículos, con personas como la clave. Las personas pueden o no pueden compartir artículos. Ejemplo:

{ 'Bob' : {'item1':3, 'item2':8, 'item3':6}, 'Jim' : {'item1':6, 'item4':7}, 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2} } 

Estoy buscando la forma más sencilla de cambiar estas relaciones y tener un nuevo diccionario nested con elementos como la clave. Ejemplo:

 {'item1' : {'Bob':3, 'Jim':6, 'Amy':6}, 'item2' : {'Bob':8, 'Amy':5}, 'item3' : {'Bob':6, 'Amy':9}, 'item4' : {'Jim':7, 'Amy':2} } 

¿Cuál es la mejor manera de hacer esto? ¿Es posible con una comprensión?

collections.defaultdict hace esto bastante simple:

 from collections import defaultdict import pprint data = { 'Bob' : {'item1':3, 'item2':8, 'item3':6}, 'Jim' : {'item1':6, 'item4':7}, 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2} } flipped = defaultdict(dict) for key, val in data.items(): for subkey, subval in val.items(): flipped[subkey][key] = subval pprint.pprint(dict(flipped)) 

Salida:

 {'item1': {'Amy': 6, 'Bob': 3, 'Jim': 6}, 'item2': {'Amy': 5, 'Bob': 8}, 'item3': {'Amy': 9, 'Bob': 6}, 'item4': {'Amy': 2, 'Jim': 7}} 

Estoy totalmente de acuerdo en que la respuesta de Ryan Ginstrom es la forma preferida de hacerlo (para todos los propósitos prácticos).

Pero como la pregunta también pregunta explícitamente:

¿Es posible con una comprensión?

Pensé que sería un buen ejemplo de cómo hacer esto con una lista de comprensión (podría ser un buen ejemplo para mostrar cómo las comprensiones de listas anidadas pueden disminuir rápidamente la legibilidad).

 import itertools d = { 'Bob' : {'item1':3, 'item2':8, 'item3':6}, 'Jim' : {'item1':6, 'item4':7}, 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2} } print dict([(x, dict([(k, d[k][x]) for k,v in d.items() if x in d[k]])) for x in set(itertools.chain(*[z for z in d.values()]))]) 

Esto es bastante fácil de hacer (como lo han demostrado otros), pero dependiendo de sus necesidades, también debe considerar que para los datos con varios datos donde desee extraerlos por cualquier criterio, una base de datos podría ser la mejor herramienta. El módulo sqlite3 incorporado proporciona una base de datos de baja sobrecarga que, dependiendo de lo que esté haciendo, puede servirle mejor que un dictado nested.

Las pandas pueden proporcionar otra opción. Supongamos que los data son el diccionario de entrada.

 import pandas as pd output = {i:s.dropna().to_dict() for i, s in pd.DataFrame(data).T.iteritems()} 

Si solo desea acceder a los diccionarios nesteds inversos, guarde la memoria si el diccionario es demasiado grande para invertir.

 class mdict2(dict): def __init__(self, parent, key1): self.parent = parent self.key1 = key1 def __getitem__(self, key2): return self.parent.mirror[key2][self.key1] class mdict(dict): def __init__(self, mirror): self.mirror = mirror def __getitem__(self, key): return mdict2(self, key) d0 = { 'Bob' : {'item1':3, 'item2':8, 'item3':6}, 'Jim' : {'item1':6, 'item4':7}, 'Amy' : {'item1':6,'item2':5,'item3':9,'item4':2} } d1 = mdict(d0) d0['Amy']['item1'] == d1['item1']['Amy'] # True