[英]How can I create nested folders with attributes in python?
我是一个初学者程序员,我刚开始学习嵌套列表和字典。 我的任务是使用 class 目录及其属性创建文件系统。
class Directory:
def __init__(self, name: str, parent: Optional['Directory'], children: List[Optional['Directory']]):
self.name = name
self.parent = parent
self.children = children
我应该构建一个 function 以递归方式创建这个文件系统,给定 root 及其字典中的目录。 Parent 是一个目录,其中包含当前目录作为他的孩子之一。 任何没有子目录的目录都应该是一个空目录。
"root": ["dirA", "dirB"],
"dirA": ["dirC"],
"dirC": ["dirH", "dirG"],
"dirB": ["dirE"]
"dirG": ["dirX", "dirY"]}
我一直在尝试这样做,我想我知道如何递归地创建目录,但是我不知道在没有任何额外导入的情况下将什么放在 dir.parent 位置。 使用root,没有问题,因为它是None,但在进一步的过程中,我不知道如何将孩子的父母(应该是Directory)作为他的属性之一,因为我将从那里递归。 你知道怎么做吗? 这是我到目前为止的代码:
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_root
方法都是完全没有必要的。 BFS 方法仅受可用堆 memory 的限制。 DFS 方法也可能受到堆栈大小的限制。
在上课之前,我们可以考虑一个普通的 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], ["."])
使用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
使用paths
可以让我们轻松创建我们需要的目录 -
import os
for path in paths(input):
os.makedirs(path)
这是一个了解可重用模块和相互递归的机会。 此答案中的此解决方案解决了您的特定问题,而无需对另一个答案中编写的模块进行任何修改。 这种方法的明显优势是tree
对节点形状的了解为零,并允许您定义任何 output 形状。
下面我们使用具有name
、 parent
和children
属性的普通dict
创建一棵树。 tree
不会为您做出这个选择。 如果需要,可以使用不同的结构或自定义 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": []
}
]
}
]
为了使用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')
]
而且我们还定义了主键和外键。 这里我们使用name
和parent
,但你可以选择任何你喜欢的名字 -
def name(t):
return t[0]
def parent(t):
return t[1]
要了解有关tree
模块及其一些好处的更多信息,请参阅原始问答
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.