首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >任意阶树的遍历

任意阶树的遍历
EN

Stack Overflow用户
提问于 2022-07-20 07:15:20
回答 1查看 35关注 0票数 0

我知道以前有人问过这个问题,我已经看到了答案,但仍然无法弄清楚到底发生了什么。

我试图根据特定的文件元数据(日期和位置)和一组条件,有条件地构建文件夹结构。例如,为了进行测试,我使用了以下方法:

代码语言:javascript
复制
COND = ["Y", "m", "C"]

这意味着,在文件夹结构中,文件需要先按年份拆分文件,然后按日历月份拆分文件,然后再按原籍国拆分文件。

这是我为测试而创建的示例数据:

代码语言:javascript
复制
data = [
    ["111", dt.datetime(2019, 1, 1), "Aus", "Bri"],
    ["112", dt.datetime(2019, 1, 5), "Aus", "Bri"],
    ["113", dt.datetime(2019, 2, 10), "Aus", "Mel"],
    ["114", dt.datetime(2020, 1, 1), "Aus", "Per"],
    ["115", dt.datetime(2020, 1, 10), "Aus", "Per"],
    ["116", dt.datetime(2020, 1, 25), "Aus", "Per"],
    ["117", dt.datetime(2020, 10, 5), "My", "KL"],
    ["118", dt.datetime(2020, 11, 6), "Ru", "Led"],
    ["119", dt.datetime(2020, 12, 1), "Ru", "Mos"],
    ["120", dt.datetime(2021, 3, 5), "Aus", "Syd"],
    ["121", dt.datetime(2021, 5, 1), "Aus", "Mel"],
    ["122", dt.datetime(2021, 6, 1), "Aus", "Per"],
    ["123", dt.datetime(2021, 11, 1), "Chi", "Bei"],
    ["124", dt.datetime(2021, 11, 15), "Jp", "Tok"],
    ["125", dt.datetime(2022, 1, 1), "Aus", "Per"],
    ["126", dt.datetime(2022, 3, 1), "Aus", "Bri"],
    ["127", dt.datetime(2022, 3, 5), "Aus", "Per"],
    ["128", dt.datetime(2022, 3, 11), "My", "KL"],
    ["129", dt.datetime(2022, 5, 1), "Aus", "Syd"],
    ["130", dt.datetime(2022, 8, 8), "Aus", "Bri"],
]

这些简单的函数执行过滤:

代码语言:javascript
复制
def filter_year(data: list[list[str | dt.datetime]]) -> list[int]:
    return {i[1].year for i in data}


def filter_month(data: list[list[str | dt.datetime]]) -> list[int]:
    return {i[1].month for i in data}


def filter_day(data: list[list[str | dt.datetime]]) -> list[int]:
    return {i[1].day for i in data}


def filter_country(data: list[list[str | dt.datetime]]) -> list[str]:
    return {i[2] for i in data}


def filter_city(data: list[list[str | dt.datetime]]) -> list[str]:
    return {i[3] for i in data}

condition_dict = {
    "Y": {'fun': filter_year, 'id': 1 },
    "m": {'fun': filter_month,'id': 1 },
    "d": {'fun': filter_day,'id': 1},
    "C": {'fun': filter_country, 'id': 2},
    "c": {'fun': filter_city, 'id': 3 }

我试图使用任意顺序树自动构建结构。节点上的数据分割工作正常:

代码语言:javascript
复制
from typing import Any
from pathlib import Path
from dataclasses import dataclass, field

@dataclass
class Node:
    folder: Path
    metadata: list[list[Any]] = field(default_factory=list)
    conditions: list[str] = field(default_factory=list)
    
    @property
    def children(self) -> list['Node']:
        if len(self.conditions) == 0:
            return []
        current_condition = self.conditions[0]
        fun = condition_dict[current_condition]['fun']
        
        fnames: list[int | str] = fun(self.metadata)
        children_data = {str(n): {} for n in fnames}
        for f in fnames:
            children_data[str(f)]['folder'] = self.folder / str(f)    
            children_data[str(f)]['conditions'] = self.conditions[1:]   
            if current_condition == 'Y':
                children_data[str(f)]['metadata'] = [i for i in self.metadata if i[1].year == f]
            elif current_condition == 'm':
                children_data[str(f)]['metadata'] = [i for i in self.metadata if i[1].month == f]
            elif current_condition == 'd':
                children_data[str(f)]['metadata'] = [i for i in self.metadata if i[1].day == f]    
            elif current_condition == 'C':
                children_data[str(f)]['metadata'] = [i for i in self.metadata if i[2] == f]
            elif current_condition == 'c':
                children_data[str(f)]['metadata'] = [i for i in self.metadata if i[3] == f]
        
        return [Node(**i) for i in children_data.values()]

现在,我正在尝试遍历我在这里使用了一个修改版本的树(Traverse Non-Binary Tree)

代码语言:javascript
复制
@dataclass
class Tree:
    def traverse(self, root: Node):
        r = root.children
        if not r or len(root.conditions) == 0:
            print('The end of subtree:', root.folder)
        else:
            for child in r:            
                print('\n'.join(str(i.folder) for i in r))
                if isinstance(child, Node):
                    for x in self.traverse(child):
                        print(str(x.folder))
                else:
                    print(child) 

但是,当我在几个正确的输出之后尝试处理我的数据时,我总是会遇到错误NoneType is not iterable

代码语言:javascript
复制
n = Node(folder=Path('/home'), metadata=data, conditions=COND)

tree = Tree()
tree.traverse(n)

输出:

代码语言:javascript
复制
/home/2019
/home/2020
/home/2021
/home/2022
/home/2019/1
/home/2019/2
/home/2019/1/Aus
The end of subtree: /home/2019/1/Aus
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in <cell line: 4>()
      1 n = Node(folder=Path('/home'), metadata=data, conditions=COND)
      3 tree = Tree()
----> 4 tree.traverse(n)

/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in Tree.traverse(self, root)
     45 print('\n'.join(str(i.folder) for i in r))
     46 if isinstance(child, Node):
---> 47     for x in self.traverse(child):
     48         print(str(x.folder))
     49 else:

/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in Tree.traverse(self, root)
     45 print('\n'.join(str(i.folder) for i in r))
     46 if isinstance(child, Node):
---> 47     for x in self.traverse(child):
     48         print(str(x.folder))
     49 else:

/home/pavel/python/photo_manager/temp/tree_test.ipynb Cell 4 in Tree.traverse(self, root)
     45 print('\n'.join(str(i.folder) for i in r))
     46 if isinstance(child, Node):
---> 47     for x in self.traverse(child):
     48         print(str(x.folder))
     49 else:

TypeError: 'NoneType' object is not iterable

我不明白为什么会发生这样的事情,因为我相信我是在防范NoneType。由于某种原因,我只会到达一个子树的末尾,而不是遍历其他子树。我在这里做错什么了?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-20 11:37:54

我并没有真正了解整个故事,但你在这条线上可能会犯这样的错误:

代码语言:javascript
复制
 for x in self.traverse(child):

问题是self.traverse没有return语句,因此这个递归调用返回None,而for x in None没有任何意义。

我认为您实际上不想从递归调用中获得一些x值,因为递归调用处理自己的事务。不需要再次打印该递归调用已经打印的内容。

这里还有第二个问题:

代码语言:javascript
复制
        for child in r:            
            print('\n'.join(str(i.folder) for i in r))

在这里,对于r中的每个子节点,您可以在print调用中再次迭代r 。只会打印副本。您只需从r中打印当前子程序即可。这将使下面的else块过时:当您刚刚打印child.folder时,似乎没有必要再次打印child

因此,纠正这两个问题,以下操作至少不会出错:

代码语言:javascript
复制
@dataclass
class Tree:
    def traverse(self, root: Node):
        r = root.children
        if not r or len(root.conditions) == 0:
            print('The end of subtree:', root.folder)
        else:
            for child in r:
                print(str(child.folder))
                if isinstance(child, Node):
                    self.traverse(child)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73047407

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档