approximatenumber
approximatenumber

Reputation: 507

Make dict from list of paths

I have a list of paths:

paths = [
   "root/child1/file1",
   "root/child1/file2",
   "root/child2/file1"
]

And I want to parse it ith python into dict (or list of dicts) that looks like:

{
    "text": "root",
    "children": [
        {
            "text": "child1",
            "children": [
                {
                    "text": "file1",
                    "children": []
                },
                {
                    "text": "file2",
                    "children": []
                }
            ]
        },
        {
            "text": "child2",
            "children": [
                {
                    "text": "file2",
                    "children": []
                }
            ]
        }

I tried to write some recursive function, but no success. Example:

def path2dict(path, depth):
    d = {}
    text = path.split('/')[0]
    d['text'] = text
    depth = depth + 1
    d['children'] = [path2dict(p, depth) for p in path.split('/')[depth:]]
    return d

paths = [
   "root/child1/file1",
   "root/child1/file2",
   "root/child2/file1"
]

depth = 0
for path in paths:
    d = path2dict(path, depth)
    print(d)

Upvotes: 3

Views: 331

Answers (2)

Ajax1234
Ajax1234

Reputation: 71451

You can use itertools.groupby:

from itertools import groupby
import json
d = ['root/child1/file1', 'root/child1/file2', 'root/child2/file1']
def create_paths(paths): 
  _vals = [[a, [c for _, *c in b]] for a, b in groupby(sorted(paths, key=lambda x:x[0]), key=lambda x:x[0])]
  return [{'text':a, 'children':[] if not b[0] else create_paths(b)} for a, b in _vals]

print(json.dumps(create_paths([i.split('/') for i in d]), indent=4))

Output:

[
   {
    "text": "root",
    "children": [
        {
            "text": "child1",
            "children": [
                {
                    "text": "file1",
                    "children": []
                },
                {
                    "text": "file2",
                    "children": []
                }
            ]
        },
        {
            "text": "child2",
            "children": [
                {
                    "text": "file1",
                    "children": []
                }
            ]
          }
      ]
   }
]

Upvotes: 0

sanyassh
sanyassh

Reputation: 8510

Sorry for not using your existing solution, but I have some other:

def stage1(paths):
    result = {}
    for path in paths:
        split = path.split('/')
        current = result
        for part in split:
            current.setdefault(part, {})
            current = current[part]
    return result


def stage2(dct):
    return [
        {
            'text': key,
            'children': stage2(value)
        }
        for key, value in dct.items()
    ]


after_stage1 = stage1(paths)

# after_stage1 is
# {
#     'root': {
#         'child1': {
#             'file1': {},
#             'file2': {}
#         },
#         'child2': {
#             'file1': {}
#         }
#     }
# }

after_stage2 = stage2(after_stage1)

# after_stage2 contains exactly what you need

Upvotes: 1

Related Questions