Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cut a very "deep" json or dictionary in Python?

I have a json object which is very deep. In other words I have a dictionary, containing dictionaries containing dictionaries and so on many times. So, one can imagine it as a huge tree in which some nodes are very far from the root node.

Now I would like to cut this tree so that I have in it only nodes that are separated not more than N steps from the root. Is there a simple way to do it?

For example if I have:

{'a':{'d':{'e':'f', 'l':'m'}}, 'b':'c', 'w':{'x':{'z':'y'}}}

And I want to keep only nodes that are 2 steps from the root, I should get:

{'a':{'d':'o1'}, 'b':'c', 'w':{'x':'o2'}}

So, I just replace the far standing dictionaries by single values.

like image 625
Roman Avatar asked Oct 16 '15 14:10

Roman


2 Answers

Given that your data is very deep, you may very well run into stack limits with recursion. Here's an iterative approach that you might be able to clean up and polish a bit:

import collections

def cut(dict_, maxdepth, replaced_with=None):
    """Cuts the dictionary at the specified depth.

    If maxdepth is n, then only n levels of keys are kept.
    """
    queue = collections.deque([(dict_, 0)])

    # invariant: every entry in the queue is a dictionary
    while queue:
        parent, depth = queue.popleft()
        for key, child in parent.items():
            if isinstance(child, dict):
                if depth == maxdepth - 1:
                    parent[key] = replaced_with
                else:
                    queue.append((child, depth+1))
like image 166
jme Avatar answered Sep 24 '22 23:09

jme


def prune(tree, max, current=0):
    for key, value in tree.items():
        if isinstance(value, dict):
            if current == max:
                tree[key] = None
            else:
                prune(value, max, current + 1)

This is mostly an example to get you started. It prunes the dictionary in place. E.g.:

>>> dic = {'a':{'d':{'e':'f', 'l':'m'}}, 'b':'c', 'w':{'x':{'z':'y'}}}
>>> prune(dic, 1)
>>> dic
{'b': 'c', 'w': {'x': None}, 'a': {'d': None}}
like image 44
deceze Avatar answered Sep 21 '22 23:09

deceze