0

I am trying to build a tree hierarchy with python lets say I have his structure, I need to be able to add more children dynamically to e.g Bannana. I think my question is a bit unclear

UPDATE: I need to create a structure like this, But The values will change so I need to create function to pass a int and create that amount of Apple(Children) and to to do the same for Lemon and all the other children. Also the Apple node is Root Node.

Apple
   Bannana
   Lemon
      Juice
        Drink
   Watermelon
       Red
         Round

But then I can Have a totally diffrent strucutre where e.g

Apple
   Bannana
   Lemon
      Juice
        Drink
          Watermelon
       Red
          Round

Json Ouptut would be

{
    'Apple': 'Fruit',
    'children': [{
        'Bannana': 'fruit',
        'children': None
    },  {
        'Lemon': 'Fruit',
        'children': [{
            'Juice': 'Food',
            'children': [{
                'Drink': 'Action',
                'children': None
             And so on...

How can make the hierarchy dynamic? For example the Number of rows under a specific parent?

I have tried something like that from an example I found

import collections
def add_element(root, path, data):
    if len(path) == 1:
        root[path[0]] = data
    else:
        add_element(root[path[0]], path[1:], data)

count = 1


tree = lambda: collections.defaultdict(tree)
root = tree()
n= 10
for i in range(1,n):
    path_list= ['Apple', 'Lemon', 'Juice' + str(count)]
    print (path_list)
    count += 1
    add_element(root,path_list, 1 )
print (root)

EDIT 1

As per the Answer I have modfied the code a bit

args = {'Apple': 'Apple', 'Lemon': 'Lemon', 'Juice': 'Juice', 'Drink': 'Drink'}

s = """
{Apple}
   {Lemon}
      {Juice}
         {Drink}
""".format(**args)

def group_data(vals):
  if len(vals) == 1:
     return {vals[0]:'Fruit', 'Children':None}
  new_data = [list(b) for _, b in itertools.groupby(vals, key=lambda x:bool(re.findall('^\s', x)))]
  new_group = [[new_data[i], new_data[i+1]] for i in range(0, len(new_data), 2)]
  result = []
  for a, b in new_group:
     result.extend([{i:'Fruit', 'Children':None} for i in a[:-1]])
     result.append({a[-1]:'Fruit', 'Children':group_data([re.sub('^\s{3}', '', c) for c in b])})
  return result

_new_data = [i.strip('\n') for i in filter(None, s.split('\n'))]


print(json.dumps(group_data(_new_data), indent=4))

this works fine but its still hardcoded which is not what im looking for.

0

1 Answer 1

1

You can analyze the whitespace before each fruit:

s = """
Apple
   Bannana
   Lemon
      Juice
         Drink
            Watermelon
      Red
         Round
"""

import itertools, re
def group_data(vals):
  if len(vals) == 1:
     return {vals[0]:'Fruit', 'Children':None}
  new_data = [list(b) for _, b in itertools.groupby(vals, key=lambda x:bool(re.findall('^\s', x)))]
  new_group = [[new_data[i], new_data[i+1]] for i in range(0, len(new_data), 2)]
  result = []
  for a, b in new_group:
     result.extend([{i:'Fruit', 'Children':None} for i in a[:-1]])
     result.append({a[-1]:'Fruit', 'Children':group_data([re.sub('^\s{3}', '', c) for c in b])})
  return result

_new_data = [i.strip('\n') for i in filter(None, s.split('\n'))]

import json
print(json.dumps(group_data(_new_data), indent=4))

Output:

[
     {
       "Apple": "Fruit",
       "Children": [
         {
            "Bannana": "Fruit",
            "Children": null
           },
           {
               "Lemon": "Fruit",
               "Children": [
                  {
                      "Juice": "Fruit",
                       "Children": [
                            {
                             "Drink": "Fruit",
                             "Children": {
                                 "Watermelon": "Fruit",
                                 "Children": null
                              }
                          }
                      ]
                  },
                  {
                       "Red": "Fruit",
                       "Children": {
                          "Round": "Fruit",
                          "Children": null
                     }
                  }
              ]
          }
       ]
    }
]
Sign up to request clarification or add additional context in comments.

3 Comments

Thats, a really good answer, but how could i do if I have dynamic values?
@WojtekT This will work for any valid structure. Can you clarify what you mean by "dynamic values"?
Dynamically I mean For Example I want to have 10 RootChild Nodes then I want to put in 2 children in every second RootChild Node

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.