如何递归地编写嵌套for循环?

2024-09-30 22:27:29 发布

您现在位置:Python中文网/ 问答频道 /正文

我有以下处理XML文件的代码:

for el in root:
    checkChild(rootDict, el)
    for child in el:
        checkChild(rootDict, el, child)
        for grandchild in child:
            checkChild(rootDict, el, child, grandchild)
            for grandgrandchild in grandchild:
                checkChild(rootDict, el, child, grandchild, grandgrandchild)
                ...
                   ...

正如您所看到的,在每次迭代中,我都只使用一个额外的参数调用同一个函数。有没有一种方法可以避免编写这么多基本上做相同事情的嵌套for循环?你知道吗

任何帮助都将不胜感激。非常感谢。你知道吗


Tags: 文件方法函数代码inchildfor参数
3条回答
def recurse(tree):
    """Walks a tree depth-first and yields the path at every step."""
    # We convert the tree to a list of paths through it,
    # with the most recently visited path last. This is the stack.
    def explore(stack):
        try:
            # Popping from the stack means reading the most recently
            # discovered but yet unexplored path in the tree. We yield it
            # so you can call your method on it.
            path = stack.pop()
        except IndexError:
            # The stack is empty. We're done.
            return
        yield path
        # Then we expand this path further, adding all extended paths to the
        # stack. In reversed order so the first child element will end up at
        # the end, and thus will be yielded first.
        stack.extend(path + (elm,) for elm in reversed(path[-1]))
    yield from explore([(tree,)])

# The linear structure yields tuples (root, child, ...)
linear = recurse(root)

# Then call checkChild(rootDict, child, ...)
next(linear)  # skip checkChild(rootDict)
for path in linear:
    checkChild(rootDict, *path[1:])

为了便于理解,假设根看起来像这样:

root
  child1
    sub1
    sub2
  child2
    sub3
      subsub1
    sub4
  child3

那就像一棵树。我们可以通过这棵树找到一些路径,例如(root, child1)。当您将这些路径提供给checkChild时,这将导致调用checkChild(rootNode, child1)。最终checkChild将为树中的每个路径准确调用一次。因此,我们可以将树写为路径列表,如下所示:

[(root,),
 (root, child1),
 (root, child1, sub1),
 (root, child1, sub2),
 (root, child2),
 (root, child2, sub3),
 (root, child2, sub3, subsub1),
 (root, child2, sub4),
 (root, child3)]

此列表中路径的顺序恰好与循环结构匹配。它被称为深度优先。(另一种排序顺序,宽度优先,将首先列出所有子节点,然后列出所有子节点,最后列出所有子节点。)

上面的列表与代码中的stack变量相同,只是stack只存储它需要记住的最少数量的路径。你知道吗

总之,recurse一个接一个地生成这些路径,最后一位代码调用checkChild方法,就像您在问题中所做的那样。你知道吗

无论您希望对文件和目录执行什么操作,都可以遍历它们。在python中,我知道的最简单的方法是:

#!/usr/bin/env python

import os

# Set the directory you want to start from
root_dir = '.'
for dir_name, subdirList, file_list in os.walk(root_dir):
    print(f'Found directory: {dir_name}s')
    for file_name in file_list:
        print(f'\t{file_name}s')

在遍历时,可以将添加到组或执行其他操作

假设root来自ElemenTree解析,您可以创建一个包含每个节点的所有祖先列表的数据结构,然后cnd对此进行迭代以调用checkChild:

def checkChild(*element_chain):
    # Code placeholder
    print("Checking %s" % '.'.join(t.tag for t in reversed(element_chain)))

tree = ET.fromstring(xml)
# Build a dict containing each node and its ancestors
nodes_and_parents = {}
for elem in tree.iter():  # tree.iter yields every tag in the XML, not only the root childs 
    for child in elem:
        nodes_and_parents[child] = [elem, ] + nodes_and_parents.get(elem, [])

for t, parents in nodes_and_parents.items():
    checkChild(t, *parents)

相关问题 更多 >