繁体   English   中英

任意顺序树的遍历

[英]Traversing of arbitrary order tree

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

我正在尝试根据文件的某些元数据(日期和位置)和一组条件有条件地构建文件夹结构。 例如,为了测试我正在使用这些:

COND = ["Y", "m", "C"]

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

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

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"],
]

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

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 }

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

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()]

现在,我正在尝试遍历我使用此处答案的修改版本的树( 遍历非二叉树

@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

n = Node(folder=Path('/home'), metadata=data, conditions=COND)

tree = Tree()
tree.traverse(n)

输出:

/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。 出于某种原因,我只到达一个子树的末尾,但没有遍历其他子树。 我在这里做错了什么?

我并没有真正了解整个故事,但是您在这一行中遇到的错误是预料之中的:

 for x in self.traverse(child):

问题是self.traverse没有return语句,所以这个递归调用返回None ,并且for x in None没有意义。

我认为您实际上不想从该递归调用中获取一些x值,因为该递归调用负责自己的业务。 无需再次打印该递归调用已打印的内容。

这里还有第二个问题:

        for child in r:            
            print('\n'.join(str(i.folder) for i in r))

在这里,对于r中的每个孩子,您在print调用中再次迭代r 那只会打印重复项。 您只需从r打印当前子项。 这会使它下面的else块过时:当您刚刚打印child.folder时,似乎没有必要再次打印child

因此,纠正这两个问题,以下至少运行没有错误:

@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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM