BATMAN
BATMAN

Reputation: 373

Get the structure of the folders from the given path list as strings

Given a list of paths as:

'alpha/beta/gamma/delta alpha/beta/sigma beta/phi/pi/rho'

I want to Print it as:

-alpha
    -beta
        -gamma
            delta
        -sigma
-beta
    -phi
        -pi
            rho

Can you please help me out with this? I was able to make a list of dictionaries of dictionaries. (I am kinda lost here) There are simpler ways to do this where I can directly print the data but I want to do it in a structure such that I might be able to use this data somewhere else too.

paths = 'alpha/beta/gamma/delta alpha/beta/sigma b/f/g/h r/g/t/y q/w/er/rat'
folder_list = []

def get_children(ippath, e_dict):
    remaining_path = '/'.join(ippath.split('/')[1:])
    try:
        splitted_path = ippath.split('/')[0]
        if splitted_path:
            e_dict[splitted_path] = {}
            e_dict[splitted_path].update(get_children(remaining_path, e_dict[ippath.split('/')[0]]))
            return e_dict
        else:
            return e_dict
    except:
        return remaining_path

for path in paths.split(' '):
    end_dict = dict()
    output = get_children(path, end_dict)
    if output:
        folder_list.append(output)
        # final_list.update(output)
    else:
        continue

print(folder_list)

It gives me a list of nested dictionaries but still not what I want.

Thank you, I really appreciate the help

Upvotes: 1

Views: 223

Answers (3)

BATMAN
BATMAN

Reputation: 373

I finally got it to work.. :) Ron Serruya's suggested library helped me rethink my structure.

import json
paths = 'alpha/beta/gamma/delta alpha/beta/sigma beta/phi/pi/rho'
folder_list = {}

def get_children(ippath, e_dict):
    remaining_path = '/'.join(ippath.split('/')[1:])
    try:
        splitted_path = ippath.split('/')[0]
        if splitted_path:
            e_dict[splitted_path] = {}
            e_dict[splitted_path].update(get_children(remaining_path, e_dict[ippath.split('/')[0]]))
            return e_dict
        else:
            return e_dict
    except:
        return remaining_path

def merge_dictionaries(new_dictionary, main_dictionary):
    key = list(new_dictionary.keys())[0]
    if list(new_dictionary[key].keys())[0] in list(main_dictionary[key].keys()):
        merge_dictionaries(new_dictionary[key], main_dictionary[key])
    else:
        main_dictionary[key][list(new_dictionary[key].keys())[0]] = new_dictionary[key][list(new_dictionary[key].keys())[0]]

def main():
    for path in paths.split(' '):
        end_dict = dict()
        output = get_children(path, end_dict)
        if output:
            if list(output.keys())[0] not in list(folder_list.keys()):
                folder_list.update(output)
            else:
                merge_dictionaries(output, folder_list)
        else:
            continue
    print(str(json.dumps(folder_list, sort_keys=True, indent=4, separators=('', ''))).replace('{', '').replace('}', ''))

main()

Gives Output:

    "alpha"
        "beta"
            "gamma"
                "delta"

            "sigma"


    "beta"
        "phi"
            "pi"
                "rho"

Sorry for really bad structure of the code, I am up for suggestion to improve this structurally.

Upvotes: 0

kaya3
kaya3

Reputation: 51043

Here's a straightforward solution:

  • First, build a set of all distinct full paths, including the intermediate paths.
  • Sort the paths. This puts them in depth-first order, guaranteeing that a parent directory will always appear before its children.
  • Iterate through the paths, maintaining a stack:
    • Pop from the stack until you find the parent of the current path.
    • Print just the difference between the current path and its parent. The indentation level is determined by the length of the stack.
    • Push the current path to the stack.

To get the - symbols in the right place, we can keep track of which paths are leaf nodes in the tree. Here's the code:

def dir_tree(s):
    paths = set()
    for path in s.split():
        parts = path.split('/')
        is_leaf = True
        while parts:
            path = '/'.join(parts) + '/'
            paths.add( (path, is_leaf) )
            parts.pop()
            is_leaf = False

    stack = ['']
    for path, is_leaf in sorted(paths):
        while not path.startswith(stack[-1]):
            stack.pop()
        suffix = path[len(stack[-1]):-1]
        tabs = len(stack) - 1
        print('\t'*tabs + ('' if is_leaf else '-') + suffix)
        stack.append(path)

Output:

-alpha
    -beta
        -gamma
            delta
        sigma
-beta
    -phi
        -pi
            rho

Upvotes: 1

Ron Serruya
Ron Serruya

Reputation: 4426

Are you fine with using another library? if so, dpath will work great for this. It allows you to create dicts based on strings

https://pypi.org/project/dpath/

Upvotes: 2

Related Questions