如何在python中创建具有属性的嵌套文件夹?

如何在python中创建具有属性的嵌套文件夹?,python,recursion,nested,Python,Recursion,Nested,我是一个初学者程序员,我刚刚开始学习嵌套列表和字典。我的任务是创建一个文件系统,包括类目录及其属性 class Directory: def __init__(self, name: str, parent: Optional['Directory'], children: List[Optional['Directory']]): self.name = name self.parent = parent self.children =

我是一个初学者程序员,我刚刚开始学习嵌套列表和字典。我的任务是创建一个文件系统,包括类目录及其属性

class Directory:
    def __init__(self, name: str, parent: Optional['Directory'], children: List[Optional['Directory']]):
        self.name = name
        self.parent = parent
        self.children = children
我应该构建一个函数来递归地创建这个文件系统,给定根目录和字典中的目录。父目录是一个目录,其中包含当前目录作为其子目录之一。任何没有子目录的目录都应该是空目录

    "root": ["dirA", "dirB"],          
    "dirA": ["dirC"],
    "dirC": ["dirH", "dirG"],
    "dirB": ["dirE"]
    "dirG": ["dirX", "dirY"]}
我一直在尝试这样做,我想我知道如何递归地创建目录,但是我不知道在没有任何额外导入的情况下在dir.parent位置放置什么。对于root,并没有问题,因为它只是过程中的一部分,我不知道如何将子级的父级(应该是目录)作为他的一个属性,因为我将递归地从那个里开始。你知道怎么做吗?以下是我目前掌握的代码:

def create_system(system: Dict[str, List[str]], parent_children: List[str]) -> Optional[List[Optional['Directory']]]:
    children: List[Optional['Directory']] = []
    for child in parent_children:
        if child in system.keys():
            children.append(Directory(child, parent, create_system(system, list(system.get(child)))))
        else:
            children.append(Directory(child, parent, []))
    return children

def root(system: Dict[str, List[str]]) -> Optional['Directory']:
    return Directory("root", None, create_system(system, list(system.get("root"))))

谢谢您的回复

您的目标是转换字典

system = {
    "root": ["dirA", "dirB"],          
    "dirA": ["dirC"],
    "dirC": ["dirH", "dirG"],
    "dirB": ["dirE"]
    "dirG": ["dirX", "dirY"]
}
进入以下树:

            root
           /    \
        dirA    dirB
        /         \
      dirC        dirE
     /   \
   dirH  dirG
         /   \
       dirX  dirY
希望很明显,流程的返回值可以是根。为了保证仅在创建父文件夹后才能访问每个文件夹,可以使用基于堆栈的BFS方法,也可以使用递归DFS方法

让我们来看一个简单的BFS方法:

def create_system_bfs(system):
    root = Directory('root', None, [])
    stack = [root]  # in practice, use collections.deque([root])

    while stack:
        current = stack.pop(0)
        for child in system.get(current.name, []):
            d = Directory(child, current, [])
            current.children.append(d)
            stack.append(d)

    return root
DFS版本可能类似于:

def create_system_dfs(system):
    def create_node(name, parent):
        d = Directory(name, parent, [])
        d.children = [create_node(child, d) for child in system.get(name, [])]
        return d
    return create_node('root', None)

请记住,还有其他可能的方法。在这两种情况下,
create\u root
方法完全没有必要。BFS方法仅受可用堆内存的限制。DFS方法也可能受到堆栈大小的限制。

您的目标是转换字典

system = {
    "root": ["dirA", "dirB"],          
    "dirA": ["dirC"],
    "dirC": ["dirH", "dirG"],
    "dirB": ["dirE"]
    "dirG": ["dirX", "dirY"]
}
进入以下树:

            root
           /    \
        dirA    dirB
        /         \
      dirC        dirE
     /   \
   dirH  dirG
         /   \
       dirX  dirY
希望很明显,流程的返回值可以是根。为了保证仅在创建父文件夹后才能访问每个文件夹,可以使用基于堆栈的BFS方法,也可以使用递归DFS方法

让我们来看一个简单的BFS方法:

def create_system_bfs(system):
    root = Directory('root', None, [])
    stack = [root]  # in practice, use collections.deque([root])

    while stack:
        current = stack.pop(0)
        for child in system.get(current.name, []):
            d = Directory(child, current, [])
            current.children.append(d)
            stack.append(d)

    return root
DFS版本可能类似于:

def create_system_dfs(system):
    def create_node(name, parent):
        d = Directory(name, parent, [])
        d.children = [create_node(child, d) for child in system.get(name, [])]
        return d
    return create_node('root', None)

请记住,还有其他可能的方法。在这两种情况下,
create\u root
方法完全没有必要。BFS方法仅受可用堆内存的限制。DFS方法也可能受到堆栈大小的限制。

在将所有的类都纠结在一起之前,我们可以用普通函数来思考-

def paths(t, init="root"):
  def loop(q, path):
    if isinstance(q, dict):
      for (dir, v) in q.items():
        yield from loop(v, [*path, dir])
    elif isinstance(q, list):
      for dir in q:
        yield from loop \
          ( t[dir] if dir in t else None
          , [*path, dir]
          )
    else:
      yield "/".join(path)
  yield from loop(t[init], ["."])
使用
路径
很容易,只需在
输入
树上调用它即可-

输入={
“根”:[“dirA”,“dirB”],
“dirA”:[“dirC”],
“dirC”:[“dirH”,“dirG”],
“dirB”:[“dirE”],
“dirG”:[“dirX”,“dirY”]
}
对于路径中的路径(输入):
打印(路径)
/dirA/dirC/dirH
/dirA/dirC/dirG/dirX
/dirA/dirC/dirG/dirY
/可怕/可怕
使用
路径
可以轻松创建所需的目录-

导入操作系统
对于路径中的路径(输入):
os.makedirs(路径)

在把所有的东西都纠结在类中之前,我们可以用一个普通函数来思考-

def paths(t, init="root"):
  def loop(q, path):
    if isinstance(q, dict):
      for (dir, v) in q.items():
        yield from loop(v, [*path, dir])
    elif isinstance(q, list):
      for dir in q:
        yield from loop \
          ( t[dir] if dir in t else None
          , [*path, dir]
          )
    else:
      yield "/".join(path)
  yield from loop(t[init], ["."])
使用
路径
很容易,只需在
输入
树上调用它即可-

输入={
“根”:[“dirA”,“dirB”],
“dirA”:[“dirC”],
“dirC”:[“dirH”,“dirG”],
“dirB”:[“dirE”],
“dirG”:[“dirX”,“dirY”]
}
对于路径中的路径(输入):
打印(路径)
/dirA/dirC/dirH
/dirA/dirC/dirG/dirX
/dirA/dirC/dirG/dirY
/可怕/可怕
使用
路径
可以轻松创建所需的目录-

导入操作系统
对于路径中的路径(输入):
os.makedirs(路径)

这是一个学习可重用模块和交互递归的机会。此答案中的此解决方案解决了您的特定问题,而无需对中编写的模块进行任何修改。这种方法的显著优点是
对节点形状没有任何了解,并允许您定义任何输出形状

下面我们使用带有
名称
父属性
子属性的普通
dict
创建一个树<代码>树
不会为您做出此选择。如果需要,可以使用不同的结构或自定义类-

from tree import tree

input = {
  None: ["dirA", "dirB"],          
  "dirA": ["dirC"],
  "dirC": ["dirH", "dirG"],
  "dirB": ["dirE"],
  "dirG": ["dirX", "dirY"]
}

result = tree \
  ( flatten(input)
  , parent
  , lambda node, children:
      dict \
        ( name=name(node)
        , parent=parent(node)
        , children=children(name(node))
        )
  )

print(result)
[
{
“姓名”:“迪拉”,
“家长”:无,
“儿童”:[
{
“名称”:“dirC”,
“家长”:“迪拉”,
“儿童”:[
{
“姓名”:“dirH”,
“父项”:“dirC”,
“儿童”:[]
},
{
“姓名”:“迪格”,
“父项”:“dirC”,
“儿童”:[
{
“名称”:“dirX”,
“父项”:“dirG”,
“儿童”:[]
},
{
“姓名”:“迪里”,
“父项”:“dirG”,
“儿童”:[]
}
]
}
]
}
]
},
{
“名称”:“dirB”,
“家长”:无,
“儿童”:[
{
“名字”:“可怕”,
“父项”:“dirB”,
“儿童”:[]
}
]
}
]
为了使用
,我们定义了一种
展平
输入节点的方法-

def展平(t):
seq=链从可匹配\
(图(λ:(,k),v)
对于input.items()中的(k,v)
)
退货清单(seq)
打印(展平(输入))
[('dirA',无)
,('dirB',无)
,('dirC','dirA')
,('dirH','dirC')
,('dirG','dirC')
,(“可怕的”、“肮脏的”)
,('dirX','dirG')
,('dirY','dirG')
]
并定义了主键和外键。这里我们使用
name
parent
,但您可以选择您喜欢的名称-

def名称(t):
返回t[0]
def父级(t):
返回t[1]

要了解有关
模块及其一些优点的更多信息,请参阅这是一个了解可重用模块和交互递归的机会。此答案中的此解决方案无需任何修改即可解决您的特定问题