user2014852
user2014852

Reputation: 41

Python reversing nested dictionaries

I want to take a nested dictionary and reverse the values for example

input = { "a" : { "x": 2, "y": 3 },
          "b" : { "x": 5, "z": 7 } }
output = {'y': {'a': 3},
          'x': {'a': 2, 'b': 5},
          'z': {'b': 7} }

what I have:

def reverse_nest_dicts(nested_dict):
    reverse_nest_dict = {}
    for k, v in nested_dict:
        for k2, v2 in nested_dict.values():
            reverse_nest_dict[k2][k] = v2
    return reverse_nest_dict

Upvotes: 4

Views: 1864

Answers (5)

edd313
edd313

Reputation: 1469

Use NestedDict. First install ndicts

pip install ndicts

Then

from ndicts.ndicts import NestedDict

input_dict = {"a": { "x": 2, "y": 3 }, "b": { "x": 5, "z": 7 }}
nd = NestedDict(input_dict)
reversed_nd = NestedDict()

for key, value in nd.items():
    reversed_key = tuple(reversed(key))
    reversed_nd[reversed_key] = value

Finally

>>> reversed_nd.to_dict()
{'x': {'a': 2, 'b': 5}, 'y': {'a': 3}, 'z': {'b': 7}}

Upvotes: 0

Arthur Kim
Arthur Kim

Reputation: 1801

If the dictionary is too large, check https://stackoverflow.com/a/47151034/676214

If you want just access reverse nested dictionaries, Save memory if the dictionary is too large to reverse.

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

Upvotes: 0

Raymond Hettinger
Raymond Hettinger

Reputation: 226486

The dictionary items() and setdefault() methods make short work of this kind of problem:

>>> input = { "a" : { "x": 2, "y": 3 },
              "b" : { "x": 5, "z": 7 } }
>>> result = {}
>>> for k1, subdict in input.items():
        for k2, v in subdict.items():
            result.setdefault(k2, {})[k1] = v

>>> result
{'y': {'a': 3}, 'x': {'a': 2, 'b': 5}, 'z': {'b': 7}}

In Python 2, you can get a minor speed boost by using iteritems() instead of items().

Likewise, the use of collections.defaultdict(dict) can be a little faster than using setdefault. Of course, that will return a defaultdict instead of a dict as specified in your question.

Upvotes: 1

Amber
Amber

Reputation: 527043

for k2, v2 in nested_dict.values():

should be

for k2, v2 in v.items():

(Also note that if you're using Python 2.x, it may be more efficient to use .iteritems() instead of .items().)


You also need to make sure the sub-dictionaries are initialized - you can do this by either using defaultdict...

from collections import defaultdict
reverse_nest_dict = defaultdict(dict)

...or by using setdefault:

reverse_nest_dict.setdefault(k2, {})[k] = v2

Upvotes: 2

isedev
isedev

Reputation: 19631

Your function has three different errors. The following is what you are after:

def reverse_nest_dicts(nested_dict):
    reverse_nest_dict = {}
    for k, v in nested_dict.iteritems():
        for k2, v2 in v.iteritems():
            try:
                reverse_nest_dict[k2][k] = v2
            except KeyError:
                reverse_nest_dict[k2] = { k : v2 }
    return reverse_nest_dict

The errors are:

  • 1st for loop: using the dictionary as loop sequence will result in keys only, you want (key,value) so need to use items() or iteritems()

  • 2nd for loop: the loop sequence should be the nested dictionary, not the outer dictionary

  • you need to initialise the reverse_nest_dict values to inner dictionaries before you try to access them.

Upvotes: 1

Related Questions