Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic Way to reverse nested dictionaries

I have a nested dictionary of people and item ratings, with people as the key. people may or may not share items. Example:

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

I'm looking for the simplest way to flip these relations, and have a new nested dictionary with items as the key. Example:

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

What is the best way to do this? Is it possible with a comprehension?

like image 581
GSto Avatar asked Feb 16 '10 14:02

GSto


People also ask

How do you flatten a dictionary with nested lists and dictionaries in Python?

Basically the same way you would flatten a nested list, you just have to do the extra work for iterating the dict by key/value, creating new keys for your new dictionary and creating the dictionary at final step. For Python >= 3.3, change the import to from collections.

Can you reverse a dictionary Python?

1) Using OrderedDict() and items() method Later you make use of a reversed() function which is an in-built python method that takes an argument as the sequence data types like tuple, lists, dictionaries, etc and returns the reverse of it. Remember that reversed() method does not modify the original iterator.


2 Answers

collections.defaultdict makes this pretty 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))

Output:

{'item1': {'Amy': 6, 'Bob': 3, 'Jim': 6},
 'item2': {'Amy': 5, 'Bob': 8},
 'item3': {'Amy': 9, 'Bob': 6},
 'item4': {'Amy': 2, 'Jim': 7}}
like image 97
Ryan Ginstrom Avatar answered Oct 11 '22 05:10

Ryan Ginstrom


I totally agree that Ryan Ginstrom's answer is the preferred way of doing this (for all practical purposes).

But since the question also explicitely asks:

Is it possible with a comprehension?

I thought I'd chime in with a quick example as for how to do this with a list comprehension (it could be a good example for showing how nested list comphrehensions can quickly decrease readability).

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()]))])
like image 24
ChristopheD Avatar answered Oct 11 '22 05:10

ChristopheD