[英]How can I create nested folders with attributes in python?
I'm a beginner programmer, and I just started learning about Nested lists and dictionaries.我是一个初学者程序员,我刚开始学习嵌套列表和字典。 I have a task to create a system of files, with class Directory and it's attributes.
我的任务是使用 class 目录及其属性创建文件系统。
class Directory:
def __init__(self, name: str, parent: Optional['Directory'], children: List[Optional['Directory']]):
self.name = name
self.parent = parent
self.children = children
I'm supposed to build a function to create this system of files recursively, given root and it's directories from dictionary.我应该构建一个 function 以递归方式创建这个文件系统,给定 root 及其字典中的目录。 Parent is a directory which includes current dir as one of his children.
Parent 是一个目录,其中包含当前目录作为他的孩子之一。 Any dir which doesn't have any children is supposed to be an empty directory.
任何没有子目录的目录都应该是一个空目录。
"root": ["dirA", "dirB"],
"dirA": ["dirC"],
"dirC": ["dirH", "dirG"],
"dirB": ["dirE"]
"dirG": ["dirX", "dirY"]}
I've been trying to do this and I think I know how to create directories recursively, however I have no idea what to put in dir.parent place without any additional imports.我一直在尝试这样做,我想我知道如何递归地创建目录,但是我不知道在没有任何额外导入的情况下将什么放在 dir.parent 位置。 With root, there's no problem because it is None but further in process I don't know how to place child's parent (which is supposed to be Directory) as one of his attributes since I'm going recursively from there.
使用root,没有问题,因为它是None,但在进一步的过程中,我不知道如何将孩子的父母(应该是Directory)作为他的属性之一,因为我将从那里递归。 Do you have any idea how to do that?
你知道怎么做吗? Here's code which I have so far:
这是我到目前为止的代码:
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"))))
Thank you for any responses!感谢您的任何回复!
Your goal is to transform the dictionary您的目标是转换字典
system = {
"root": ["dirA", "dirB"],
"dirA": ["dirC"],
"dirC": ["dirH", "dirG"],
"dirB": ["dirE"]
"dirG": ["dirX", "dirY"]
}
into the following tree:进入以下树:
root
/ \
dirA dirB
/ \
dirC dirE
/ \
dirH dirG
/ \
dirX dirY
Hopefully, it's clear that the return value of the process can be just the root.希望很明显,该过程的返回值可以只是根。 To guarantee that you hit every folder only after its parent has been created, you can use either a stack-based BFS approach, or a recursive DFS approach.
为确保仅在创建父文件夹后才访问每个文件夹,您可以使用基于堆栈的 BFS 方法或递归 DFS 方法。
Let's look at a simple BFS approach:让我们看一个简单的 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
The DFS version of that could be something like:其 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)
Keep in mind that there are other possible approaches.请记住,还有其他可能的方法。 In both cases, the
create_root
method is completely unnecessary.在这两种情况下,
create_root
方法都是完全没有必要的。 The BFS approach is limited only by available heap memory. BFS 方法仅受可用堆 memory 的限制。 The DFS approach may also be limited by stack size.
DFS 方法也可能受到堆栈大小的限制。
Before get all tangled up in classes we can think in terms of an ordinary function -在上课之前,我们可以考虑一个普通的 function -
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], ["."])
Using paths
is easy, simply call it on your input
tree -使用
paths
很容易,只需在input
树上调用它 -
input = {
"root": ["dirA", "dirB"],
"dirA": ["dirC"],
"dirC": ["dirH", "dirG"],
"dirB": ["dirE"],
"dirG": ["dirX", "dirY"]
}
for path in paths(input):
print(path)
./dirA/dirC/dirH
./dirA/dirC/dirG/dirX
./dirA/dirC/dirG/dirY
./dirB/dirE
Using paths
allows us to easily create the directories we need -使用
paths
可以让我们轻松创建我们需要的目录 -
import os
for path in paths(input):
os.makedirs(path)
This is an opportunity to learn about reusable modules and mutual recursion.这是一个了解可重用模块和相互递归的机会。 This solution in this answer solves your specific problem without any modification of the modules written in another answer .
此答案中的此解决方案解决了您的特定问题,而无需对另一个答案中编写的模块进行任何修改。 The distinct advantage of this approach is that
tree
has zero knowledge of your node shape and allows you to define any output shape.这种方法的明显优势是
tree
对节点形状的了解为零,并允许您定义任何 output 形状。
Below we create a tree using plain dict
with name
, parent
, and children
properties.下面我们使用具有
name
、 parent
和children
属性的普通dict
创建一棵树。 tree
does not make this choice for you. tree
不会为您做出这个选择。 A different structure or a custom class can be used, if desired -如果需要,可以使用不同的结构或自定义 class -
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)
[
{
"name": "dirA",
"parent": None,
"children": [
{
"name": "dirC",
"parent": "dirA",
"children": [
{
"name": "dirH",
"parent": "dirC",
"children": []
},
{
"name": "dirG",
"parent": "dirC",
"children": [
{
"name": "dirX",
"parent": "dirG",
"children": []
},
{
"name": "dirY",
"parent": "dirG",
"children": []
}
]
}
]
}
]
},
{
"name": "dirB",
"parent": None,
"children": [
{
"name": "dirE",
"parent": "dirB",
"children": []
}
]
}
]
In order to use tree
, we defined a way to flatten
the input nodes -为了使用
tree
,我们定义了一种flatten
输入节点的方法 -
def flatten(t):
seq = chain.from_iterable \
( map(lambda _: (_, k), v)
for (k,v) in input.items()
)
return list(seq)
print(flatten(input))
[ ('dirA', None)
, ('dirB', None)
, ('dirC', 'dirA')
, ('dirH', 'dirC')
, ('dirG', 'dirC')
, ('dirE', 'dirB')
, ('dirX', 'dirG')
, ('dirY', 'dirG')
]
And we also defined the primary key and foreign key.而且我们还定义了主键和外键。 Here we use
name
and parent
, but you can choose whichever names you like -这里我们使用
name
和parent
,但你可以选择任何你喜欢的名字 -
def name(t):
return t[0]
def parent(t):
return t[1]
To learn more about the tree
module and some of its benefits, see the original Q&A要了解有关
tree
模块及其一些好处的更多信息,请参阅原始问答
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.