简体   繁体   中英

Python - Building A Nested tree Dynamically

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 eg 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 eg

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.

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
                     }
                  }
              ]
          }
       ]
    }
]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM