4

I have a dictionary like this:

dirDict = {"DIR1" : {
                    "DIR11" : { 
                                "DIR111" : "Maki111",
                                "DIR112" : "Maki112"
                                }, 
                    "DIR12" : "Maki12", 
                    "DIR13" : {
                                "DIR131" : "Maki131"
                                }
                }
    }

Imagine this like a folder structure. And I would like to get similar as os.walk would do with a folder structure. Something like this:

["DIR1/DIR11/DIR111/Maki111",
"DIR1/DIR11/DIR112/Maki112",
"DIR1/DIR12/Maki12",
"DIR1/DIR13/DIR131/Maki131"]

So it is basically all the path for the dictionary values. I tried it many ways with recursive functions but I got lost.

Here is my latest trial:

def walk(input_dict, path_string = "",  result = ""):
    for key, value in input_dict.items():
        if isinstance(value, dict):
            path_string += "/" + key
            print "==== DICT ====", "\nkey: ", key, "\nvalue: ", value, "\n\t\tpath_string: ", path_string
            result = walk(value, path_string)
            print "\t\t\t\tresulting: ", result
        elif isinstance(value, str):
            print "==== NOT DICT ===="
            path_string += "/" + value
            print "\t\tpath_string: ", path_string, "\nvalue: ", value
            return path_string
        else:
            path_string = "/" + key
        result += "\n" + result
    return result
Tom Zych
  • 13,329
  • 9
  • 36
  • 53
Prag
  • 529
  • 1
  • 6
  • 12

4 Answers4

3

Using Python 3:

dirDict = {"DIR1" : {
                    "DIR11" : {
                                "DIR111" : "Maki111",
                                "DIR112" : "Maki112"
                                },
                    "DIR12" : "Maki12",
                    "DIR13" : {
                                "DIR131" : "Maki131"
                                }
                }
    }

def recurse(d, prefix=None, sep='/'):
    if prefix is None:
        prefix = []
    for key, value in d.items():
        if isinstance(value, dict):
            yield from recurse(value, prefix + [key])
        else:
            yield sep.join(prefix + [key, value])

print(list(recurse(dirDict)))

Output:

['DIR1/DIR13/DIR131/Maki131', 'DIR1/DIR11/DIR111/Maki111', 'DIR1/DIR11/DIR112/Maki112', 'DIR1/DIR12/Maki12']
ojii
  • 4,729
  • 2
  • 23
  • 34
1
def walk(d, path):
    paths = []
    if len(d) == 0:
        return path
    for k, v in d.iteritems():
        child_path = path + k + '/'
        if isinstance(v, basestring):
            paths.append(child_path + v)
        else:
            paths.extend(walk(v, child_path))
    return paths
Andrey
  • 59,039
  • 12
  • 119
  • 163
0

THe walk function I posted at https://gist.github.com/nvie/f304caf3b4f1ca4c3884#gistcomment-1597937 can be used as a helper for your problem:

def walk(obj, parent_first=True):

    # Top down?
    if parent_first:
        yield (), obj

    # For nested objects, the key is the path component.
    if isinstance(obj, dict):
        children = obj.items()

    # For nested lists, the position is the path component.
    elif isinstance(obj, (list, tuple)):
        children = enumerate(obj)

    # Scalar values have no children.
    else:
        children = []

    # Recurse into children
    for key, value in children:
        for child_path, child in walk(value, parent_first):
            yield (key,) + child_path, child

    # Bottom up?
    if not parent_first:
        yield (), obj

Your problem can be approached using something like this:

for path, value in walk(obj):
    if isinstance(value, str):  # leaf node
        path_with_value = path + (value,)
        print("/".join(path_with_value))
wouter bolsterlee
  • 3,879
  • 22
  • 30
0

A compact solution with a list comprehension:

def f(v):
    if isinstance(v, dict):
        return dict_to_list(v)
    elif isinstance(v, list):
        return v
    else:
        return [v]

def dict_to_list(d):
    return ['{}/{}'.format(k, i) for k, v in d.items() for i in f(v)]

lst = dict_to_list(dirDict)
lst.sort()
print('\n'.join(lst))
Tom Zych
  • 13,329
  • 9
  • 36
  • 53