1

I have the following code to create a JSON file based on data seperated by ;. import csv from collections import defaultdict

def ctree():
    """ One of the python gems. Making possible to have dynamic tree structure.
    """
    return defaultdict(ctree)


def build_leaf(name, leaf):
    """ Recursive function to build desired custom tree structure
    """
    res = {"name": name}

    # add children node if the leaf actually has any children
    if len(leaf.keys()) > 0:
        res["children"] = [build_leaf(k, v) for k, v in leaf.items()]

    return res


def main(delimter):
    tree = ctree()
    text = """
    something;cookie;chocolat
    something;cookie;milk
    something;gains;bread
    anything;protein;chicken
    """
    rows = [row.strip().split(delimter) for row in text.split("\n")]
    for row in rows:
        if row:
            leaf = tree[row[0]]
            for cid in range(1, len(row)):
                leaf = leaf[row[cid]]

    # building a custom tree structure
    res = []
    for name, leaf in tree.items():
        res.append(build_leaf(name, leaf))

    # printing results into the terminal
    import json
    print(json.dumps(res))


# so let's roll
main(";")

(source: Convert csv to JSON tree structure? )

This will produce this output:

[
  {
    "name": ""
  },
  {
    "name": "something",
    "children": [
      {
        "name": "cookie",
        "children": [
          {
            "name": "chocolat"
          },
          {
            "name": "milk"
          }
        ]
      },
      {
        "name": "gains",
        "children": [
          {
            "name": "bread"
          }
        ]
      }
    ]
  },
  {
    "name": "anything",
    "children": [
      {
        "name": "protein",
        "children": [
          {
            "name": "chicken"
          }
        ]
      }
    ]
  }
]

However I want to inlcude a , "size" : 100, so I have an output like this:

[
  {
    "name": ""
  },
  {
    "name": "something",
    "children": [
      {
        "name": "cookie",
        "children": [
          {
            "name": "chocolat", "size" : 100
          },
          {
            "name": "milk", "size" : 100
          }
        ]
      },
      {
etc.

So actually it needs to add , "size" : 100 if an item is added to the 3rd layer. I'm wondering if this is still possible using recursion as above? or should I change it to nested loops (which I not prefer) to be able to "remember" the current layer? If not how can I achieve this while still using recursion

CodeNoob
  • 1,988
  • 1
  • 11
  • 33
  • 2
    You can add another parameter to your `build_leaf()` function. On the first run, you'll pass 0 (I'm not sure whether Python has default values for parameters, but this would be a perfect usage for it), then pass value 1 higher when the function is calling itself. – Markaos Jun 10 '17 at 22:19

1 Answers1

1

As Markaos mentions in the comments, you just need to keep track of the recursion depth so you know when to add the extra key-value pair to each dict in res["children"]. Eg,

def build_leaf(name, leaf, depth=0):
    """ Recursive function to build desired custom tree structure
    """
    res = {"name": name}
    depth += 1

    # add children node if the leaf actually has any children
    if len(leaf.keys()) > 0:
        lst = [build_leaf(k, v, depth) for k, v in leaf.items()]
        if depth >= 2:
            for d in lst:
                d['size'] = 100
        res["children"] = lst    
    return res

I've given depth a default value of zero, so you don't need to modify the call to build_leaf in main.

The resulting JSON looks like this (I've used a custom encoder to produce more compact output).

[
  {"name": ""},
  {
    "name": "something",
    "children": [
      {
        "name": "cookie",
        "children": [
          {"name": "chocolat", "size": 100},
          {"name": "milk", "size": 100}
        ]
      },
      {
        "name": "gains",
        "children": [
          {"name": "bread", "size": 100}
        ]
      }
    ]
  },
  {
    "name": "anything",
    "children": [
      {
        "name": "protein",
        "children": [
          {"name": "chicken", "size": 100}
        ]
      }
    ]
  }
]
PM 2Ring
  • 54,345
  • 6
  • 82
  • 182