3

I have a sample JSON like:

{'key1': {'key2': 2, 'key3': 1, 'key4' : 1}}

and I would like to remove each leaf node once and print the JSON using python.

For that, I have the code for printing all the leaf nodes. But, can someone help write for me the code for dynamically remove a leaf node - one at a time

def print_all_leaf_nodes(data):
    if isinstance(data, dict):
        for item in data.values():
            print_all_leaf_nodes(item)
    elif isinstance(data, list) or isinstance(data, tuple):
        for item in data:
            print_all_leaf_nodes(item)
    else:
        print data

input:

{'key1': {'key2': 2, 'key3': 1, 'key4' : 1}}

Output:

{'key1': {'key3': 1, 'key4' : 1}}
{'key1': {'key2': 2, 'key4' : 1}}
{'key1': {'key2': 2, 'key3': 1}}

i.e for each iteration, remove a key value pair if its leaf node.

Note: even i am able to get the key path from parent , but not sure how to delete the exact element .

For example if the json is

{ "key1" : { "key2" : { "key3": "value1", "key4" : "value2" }}}

i have the recursive function which returns me a string

key_to_be_removed = "key1.key2.key4"

but i am not sure how to delete key4 using this string.

please help.

boardrider
  • 5,882
  • 7
  • 49
  • 86
srinath
  • 2,748
  • 6
  • 35
  • 56

2 Answers2

0

Sounds like you have three distinct problems:

  1. Detect leaf nodes in a tree.
  2. Remove key-value pairs from a dictionary depending on some condition.
  3. Do this recursively down a tree.

You have the leaf node detection working. For the latter two, I would recommend you read up on dictionary comprehensions.

Remove Certain Values

To make a copy of a dictionary with certain values removed, you can use an if within a dictionary comprehension:

def foo(d):

    return {
        key: value
        for key, value in d.items()
        if some_condition(key, value)
    }

where some_condition is

Recursion

This is a broad topic. In the case of recursively applying a method to a dictionary and its values, you can simply include a recursive reference in your dictionary comprehension:

def foo(d):

    return {
        key: foo(value)
        for key, value in d.items()
    }
Community
  • 1
  • 1
6c1
  • 392
  • 2
  • 14
0

If I have understood you have a dict like the below:

 g = {
  2: 3,
  4:
      {
          3: 4,
          34: {
              36: 5,
              8: 5,
              7: 9,
              9: 7
          },
          8: 9,
          9: {
              3: 4
          }
      },
  89: 3
  }

This dict rapresent a general tree structure where each node could point to an item or a subtree.

If you need to iterate the tree and return the tree without a leaf for each iteration, you could use a generator. You can take advantage of the fact that python do not deep copy the dicts, so if you pass a dict to a function and than you pop an element inside the function you also pop an element outside the function:

This code is not tested please test it

# dict, void list -> dict, list
# find the deepest subtree in a nested dict and return the subtree and the path
# to find it. If there isn't subtree return the same dict and a void list
  def _mostNestedSubTree(tree, nodes):
      for key in tree:
          if isinstance(tree[key], dict):
              nodes.append(key)
              return _mostNestedSubTree(tree[key], nodes)
      return tree, nodes


  # dict, list -> dict
  # pop a nested element from a dict (tree) following the path in a list (nodes)
  def _recursivePop(tree, nodes):
      if len(nodes) > 1:
          print(tree, nodes[0])
          tree = tree[nodes[0]]
          return _recursivePop(tree, nodes[1:])
      else:
          print(tree, nodes[0])
          tree.pop(nodes[0])
          return tree


  def removeOneLeaf(tree):
      mostNestedDict, nodes = _mostNestedSubTree(tree, [])
      while mostNestedDict != tree:
          if len(mostNestedDict) > 1:
              mostNestedDict.pop(list(mostNestedDict)[0])
          else:
              _recursivePop(tree, nodes)
          mostNestedDict, nodes = _mostNestedSubTree(tree, [])
          yield tree

Another way could be create an object that better rapresent your tree, for example you can start noting that you can rapresent g with something like the below:

myTree = {
    tree: [3, 4, 5, 5, 9, 4],
    nodes: [2,4,[3,34,[36,8],8,9,[9,[3,4]]]]
    }
Community
  • 1
  • 1
Fi3
  • 429
  • 6
  • 17