Converting a nested dictionary to a list

Refresh

December 2018

Views

6.4k time

5

I know there are many dict to list questions on here but I can't quite find the information I need for my situation so I'm asking a new quetion.

Some background: I'm using a hierarchical package for my models and the built-in function which generates the tree structure outputs a nested loop to indicate parents, children, etc. My goal is to keep the logic in views and output a list so that I can simply loop over it in my templates.

Here is my data, in the tree structure:

1
-1.1
--1.1.1
---1.1.1.1
--1.1.2
-1.2
--1.2.1
--1.2.2
-1.3

Here is the nested dictionary I am getting as a result

{
 <Part: 1.1>:
 {
   <Part: 1.1.1>:
     {
       <Part: 1.1.1.1>: {}
     }, 
   <Part: 1.1.2>: {}
 },
 <Part: 1.2>: 
 {
   <Part: 1.2.1>: {},
   <Part: 1.2.2>: {}
 }, 
 <Part: 1.3>: {}
}

or if you don't like the way I tried to break it up, here is what I get in a single line:

{<Part: 1.1>: {<Part: 1.1.1>: {<Part: 1.1.1.1>: {}}, <Part: 1.1.2>: {}}, <Part: 1.2>: {<Part: 1.2.1>: {}, <Part: 1.2.2>: {}}, <Part: 1.3>: {}}

What I'd like is to get:

[<Part: 1.1>, <Part: 1.1.1>, <Part: 1.1.1.1>, <Part: 1.1.2>, <Part: 1.2>, <Part: 1.2.2>, <Part: 1.2.1>, <Part: 1.3>,]

I've tried just iterating over the key in dict.items but then I only get the top level keys (1.1, 1.2, 1.3)

What do I need to do to get deeper?

thanks!

5 answers

1

Inception ... э-э, я имею в виду, рекурсия. Попробуй это:

def recurse(dict):
    result = []
    for key in dict:
        result.append(key)
        result.extend(recurse(dict[key]))
    return result
0

Эта проблема не может быть решена путем простой итерации по словарю. Вам нужен тип алгоритма под названием рекурсивного спуска

def getKeys(D, answer):
    if not D:
        return
    else:
        for k in D:
            answer.append(k)
            getKeys(D[k], answer)

if __name__ == "__main__":
    d = {"<Part: 1.1>": {"<Part: 1.1.1>": {"<Part: 1.1.1.1>": {}}, "<Part: 1.1.2>": {}}, "<Part: 1.2>": {"<Part: 1.2.1>": {}, "<Part: 1.2.2>": {}}, "<Part: 1.3>": {}}
    answer = []
    getKeys(d, answer)
    print answer

Это было проверено и работает

Надеюсь это поможет

10

Я думаю, что рекурсия может быть ваш друг:

top = {"<Part: 1.1>": {"<Part: 1.1.1>": {"<Part: 1.1.1.1>": {}}, "<Part: 1.1.2>": {}}, "<Part: 1.2>": {"<Part: 1.2.1>": {}, "<Part: 1.2.2>": {}}, "<Part: 1.3>": {}}

 def grab_children(father):
    local_list = []
    for key, value in father.iteritems():
        local_list.append(key)
        local_list.extend(grab_children(value))
    return local_list

print grab_children(top)
0

На основании ответа Михая: вы должны сортировать ключи, иначе вы, вероятно, есть проблемы:

def recurse(d):
    result = []
    for key in sorted(d.keys()):
        result.append(key)
        result.extend(recurse(d[key]))
    return result
2

Все предыдущих решений строить много списков рекурсивны, а затем распространить их обратно в большие и большие списки, пока вы не окончательный ответа. В то время как это работает, это не является оптимальным с точки зрения производительности, так как она создает много списков, которые на самом деле не нужны, и включает в себя расширение одни и те же вещи много раз в свои родительских списки. Некоторые решения также забывают сортировать по клавишам.

top = {"<Part: 1.1>": {"<Part: 1.1.1>": {"<Part: 1.1.1.1>": {}}, "<Part: 1.1.2>": {}}, "<Part: 1.2>": {"<Part: 1.2.1>": {}, "<Part: 1.2.2>": {}}, "<Part: 1.3>": {}}

def flatten(d, ret=None):
    if ret is None:
        ret = []
    for k, v in sorted(d.items()):
        ret.append(k)
        if v:
            flatten(v, ret)
    return ret

def test():
    flatten(top)

Согласно python -m timeit -s "import flatten" "flatten.test()", этот метод использует 8,57 usecs за цикл, по сравнению с 14,4 usecs на петле для Cedrics ответа, при обновлении также сортировать вывод правильно ( for key, value in sorted(father.items()):)