遍历/迭代任意深度的嵌套字典(字典表示目录树)

2022-01-24 00:00:00 python 递归 dictionary iteration tree

问题描述

我几乎可以肯定有一个简单的解决方案,但我现在花了几个小时阅读和重新阅读同一组相关结果,这些结果并不能完全回答我的问题.

I am almost certain there is a simple solution to this, but I have spent hours now reading and rereading the same set of related results that don't quite answer my problem.

这个问题的背景(包括在内,但可以跳过这个)

这是因为我希望用户能够从目录(以及任何子目录)中选择一组文件,不幸的是,Tkinter 在文件对话框中选择多个文件的默认功能在 Windows 7 上被破坏(http://bugs.python.org/issue8010).

This came up because I want a user to be able to select a group of files from within a directory (and also any subdirectory), and unfortunately Tkinter's default ability for selecting multiple files in a file dialog is broken on Windows 7 (http://bugs.python.org/issue8010).

因此,我试图通过另一种方法(仍然使用 Tkinter)来表示目录结构:构建目录结构的副本,由标记和缩进的复选框组成(以树的形式组织).因此,像这样的目录:

Thus I am attempting to represent a directory structure by an alternative method (still using Tkinter): constructing a facsimile of the directory structure, made of labeled and indented checkboxes (organized in a tree). Thus a directory like this:

SomeRootDirectory
    foo.txt
    ar.txt
    Stories
        Horror
            scary.txt
            Trash
                
otscary.txt
        Cyberpunk
    Poems
        doyoureadme.txt

看起来像这样(其中 # 代表一个复选按钮):

will look something like this (where # represents a checkbutton):

SomeRootDirectory
    # foo.txt
    # bar.txt
    Stories
        Horror
            # scary.txt
            Trash
                # notscary.txt
        Cyberpunk
    Poems
        # doyoureadme.txt

使用我在 ActiveState 中找到的某个配方(见下文)很容易从目录结构构建原始字典,但是当我尝试遍历我留下的嵌套良好的字典时,我碰壁了.而且我认为我需要对其进行迭代,以便用树的漂亮网格表示填充 Tkinter 框架.然后我希望通过解释哪些复选框是真或假来加载用户选择的各种文本文件.除了迭代字典没有固定深度之外,一切似乎都相当简单.

Building the original dictionary from the directory structure is easy using a certain recipe I found at ActiveState (see below), but I hit a wall when I try to iterate over the nicely nested dictionary I am left with. And I think I need to iterate over it in order to populate a Tkinter frame with a pretty gridded representation of the tree. Then I hope to load in the various text files selected by the user, by interpreting which checkboxes were true or false. Everything seems fairly easy except iterating over the dictionary without fixing the depth.

更抽象的说法

为了制作这些嵌套字典,我使用了 ActiveState 配方 -- http://code.activestate.com/recipes/577879/.它实现了 os.walk 来制作这样的字典:

To make these nested dictionaries I am using an ActiveState recipe -- http://code.activestate.com/recipes/577879/. It implements os.walk to make dictionaries such as this:

a={
    'SomeRootDirectory': {
        'foo.txt': None,
        'bar.txt': None,
        'Stories': {
            'Horror': {
                'horror.txt' : None,
                'Trash' : {
                    'notscary.txt' : None,
                    },
                },
            'Cyberpunk' : None
            },
        'Poems' : {
            'doyoureadme.txt' : None
        }
    }
}

在那之后我被难住了.在撰写本文时,我是一名 Python 新手

After which point I am stumped. I am a Python newbie at time of writing

根据 spicavigo 的回复改编的解决方案

#distinguish between directory and file
dirtab = "/==="
filetab = "|---"

Parents={-1:"Root"}
def add_dir(level, parent, index, k):
    print (dirtab*level)+k
def add_file(level, parent, index, k):
    #Currently an empty folder gets passed to add_file; here's a quick treatment.
    if "." in k:
        print (filetab*level)+k
    else:
        print (dirtab*level)+k
def addemup(level=0, parent=-1, index=0, di={}):
    for k in di:
        index +=1
        if di[k]:
            Parents[index]=k
            add_dir(level, parent, index, k)
            addemup(level+1, index, index, di[k])
        else:
            add_file(level, parent, index, k)

addemup(di=a) #dictionary from above

这产生了一些我认为很容易修改为 Tkinter 表示的东西:

This produces something that I think will be very easy to revise into a Tkinter representation:

SomeRootDirectory
/===Poems
|---|---doyoureadme.txt
/===Stories
/===/===Horror
|---|---|---rickscott.txt
/===/===/===Trash
|---|---|---|---notscary.txt
/===/===Cyberpunk
|---foo.txt
|---bar.txt

谢谢,这个社区太棒了.

Thanks, this community is incredible.


解决方案

这是一个初步的代码.仔细阅读并告诉我您面临的问题.

This is a preliminary code. Go through it and tell me where you face problems.

Parents={-1:"Root"}
def add_dir(level, parent, index, k):
    print "Directory"
    print "Level=%d, Parent=%s, Index=%d, value=%s" % (level, Parents[parent], index, k)
def add_file(parent, index, k):
    print "File"
    print "Parent=%s, Index=%d, value=%s" %  (Parents[parent], index, k)
def f(level=0, parent=-1, index=0, di={}):
    for k in di:
        index +=1
        if di[k]:
            Parents[index]=k
            add_dir(level, parent, index, k)
            f(level+1, index, index, di[k])
        else:
            add_file(parent, index, k)

a={
    'SomeRootDirectory': {
        'foo.txt': None,
        'bar.txt': None,
        'Stories': {
            'Horror': {
                'rickscott.txt' : None,
                'Trash' : {
                    'notscary.txt' : None,
                    },
                },
            'Cyberpunk' : None
            },
        'Poems' : {
            'doyoureadme.txt' : None
        }
    }
}

f(di=a)

相关文章