我实际上正在使用Jython,而且我对Python的做法很新......
当我使用javax.swing.tree.DefaultMutableTreeNode时,我可以直接使用depth / breadthFirstEnumeration()......
但是,如果我正在使用DOM树(例如来自XML),那么就没有这样的等价物......但是我觉得必须有一种非常优雅和强大的方法在Python / Jython中使用递归发生器。
希望我想要的是实用程序方法的最一般目的,它实际上会对你可以抛出的任何类型的树对象进行枚举...所以你可能必须提供给你的孩子的方法给定节点...在org.w3c.dom.Node的情况下,这将是getChildNodes()...那么你可能需要第二个可选的param来指定深度或广度......
令我惊讶的是,例如,通过Google搜索或查看此处,我无法找到简单的答案。
答案 0 :(得分:2)
AFAIK,没有内置实现。一个非常直接的解决方案是:
import collections
def depth_first_search(node, get_children, depth=0):
yield node, depth
for child in get_children(node):
# In the upcoming Python 3.3, the following can be written as
# yield from depth_first_search(child, get_children, depth + 1)
for n, d in depth_first_search(child, get_children, depth + 1):
yield n, d
def breadth_first_search(node, get_children, depth=0):
queue = collections.deque([(node, depth)])
while queue:
node, depth = queue.popleft()
queue.extend((n, depth + 1) for n in get_children(node))
yield node, depth
然后您可以按如下方式轻松使用这些:
def dom_get_children(node):
nodeList = node.getNodeList()
for i in range(nodeList.getLength()):
yield nodeList.item(i)
for node, depth in depth_first_search(some_dom_element, dom_get_children):
# do something
答案 1 :(得分:0)
免责声明:我在Ferdinand提出他的优秀答案的最终版本之前写过这篇文章
实际上你的解决方案似乎适用于由常规Python列表组成的树...不幸的是org.w3c.dom.Node特别“钝”... getChildNodes()实际上产生了一个名为NodeList的对象,虽然显然是某种列表(Java数组)仍然与内省密切相关...特别是,dir()会告诉你它的“childNodes”字段的类是“org.apache.xerces.dom.DeferredElementImpl” “......我的经验是,以”Impl“结尾的任何事情都不会让玩起来很有趣......
因此我很明显找不到将方法作为参数传递并调用它的方法......即使使用更类似Python的类,我目前还不清楚如何调用作为参数传递的方法...反正...
以下是我的3个产品,非常不言自明:1)深度优先2)深度或宽度优先选择3)相同但提供深度指示的东西(因此您可以格式化打印输出例如)。 对于解决方案#3,遗憾的是我被迫创建了一个新类,因为我发现例如向Node对象添加一个属性是不可能的......显然Jython与Python相比具有局限性和“杂质”。我知道有处理XML等的python模块......将在适当的时候调查它。 (当然,注意Jython的一个很好的方面是你可以将逐渐从Java过渡到Python)。
如果有经验的Python / Jython人有任何评论,那么会感兴趣吗...
深度优先:
def depthFirstTreeEnumeration( node ):
nodeList = node.getChildNodes()
for i in range( nodeList.getLength()):
childNode = nodeList.item( i )
yield childNode
for item in depthFirstTreeEnumeration( childNode ):
yield item
选择深度或广度优先
def treeEnumeration( node, depthFirst = True ):
nodeList = node.getChildNodes()
for i in range( nodeList.getLength()):
childNode = nodeList.item( i )
yield childNode
if depthFirst:
for item in treeEnumeration( childNode ):
yield item
if not depthFirst:
for i in range( nodeList.getLength()):
childNode = nodeList.item( i )
for item in treeEnumeration( childNode, False ):
yield item
选择深度或广度优先,并指示给定节点的深度
class NodeWrapper():
def __init__(self, node, depth ):
self.node = node
self.depth = depth
def __repr__( self ):
return "node %s, depth %d" % (self.node, self.depth)
def treeEnumerationShowDepth( node, depth = 0, depthFirst = True ):
nodeList = node.getChildNodes()
for i in range( nodeList.getLength()):
wrapper = NodeWrapper( nodeList.item( i ), depth )
yield wrapper
if depthFirst:
for item in treeEnumerationShowDepth( wrapper.node, depth + 1 ):
yield item
if not depthFirst:
for i in range( nodeList.getLength()):
childNode = nodeList.item( i )
for item in treeEnumerationShowDepth( childNode, depth + 1, False ):
yield item
from org.w3c.dom import Node
for wrapper in treeEnumerationShowDepth( dom.getDocumentElement(), 0, False ):
print "%snode: %s" % ( wrapper.depth * " ", wrapper.node )