我有一个函数,计算一些简单的node.id,node.parentId关联的treeNodes集合的左右节点值。它非常简单并且运作良好......但是,我想知道是否有更习惯的方法。特别是有没有一种方法来跟踪左/右值,而不使用一些外部跟踪值,但仍然保持美味的递归。我该如何使这种方法更Scalalicious
/*
* A tree node
*/
case class TreeNode(val id:String, val parentId: String){
var left: Int = 0
var right: Int = 0
}
/*
* a method to compute the left/right node values
*/
def walktree(node: TreeNode) = {
/*
* increment state for the inner function
*/
var c = 0
/*
* A method to set the increment state
*/
def increment = { c+=1; c } // poo
/*
* the tasty inner method
* treeNodes is a List[TreeNode]
*/
def walk(node: TreeNode): Unit = {
node.left = increment
/*
* recurse on all direct descendants
*/
treeNodes filter(_.parentId == node.id) foreach (walk(_))
node.right = increment
}
walk(node)
}
walktree(someRootNode)
编辑 - 节点列表取自数据库。将节点拉入适当的树会花费太多时间。我正在将一个单子列表放入记忆中,而我所拥有的是一个通过节点标识符与父母和孩子相关的关联。
添加左/右节点值允许我通过单个SQL查询获得所有儿童(和儿童儿童)的快照。
如果父母 - 子女关联发生变化(他们经常这样做),计算需要非常快速地执行以保持数据完整性。
除了使用令人敬畏的Scala集合外,我还通过对树节点上的某些前/后过滤使用并行处理来提高速度。我想找到更加习惯的方式来跟踪左/右节点值。从@dhg看到答案后,情况变得更好了。使用groupBy而不是过滤器可以使算法(主要是?)线性而不是四边形!
val treeNodeMap = treeNodes.groupBy(_.parentId).withDefaultValue(Nil)
def walktree(node: TreeNode) = {
def walk(node: TreeNode, counter: Int): Int = {
node.left = counter
node.right =
treeNodeMap(node.id)
.foldLeft(counter+1) {
(result, curnode) => walk(curnode, result) + 1
}
node.right
}
walk(node,1)
}
'treeNodes'定义在哪里?有没有理由你没有递归定义TreeNode? 'walktree'有什么意义?重新编号“左”和“右”值?为什么不是与'TreeNode's相关的'left'和'right'值? – dhg 2012-04-11 16:10:13
这不是codereview,但你需要少量评论,而且你至少需要一个有用的评论。您的评论完全为零说明代码尚未告诉您的任何相关内容。把它们全部扔掉,并添加两行描述目标。 – 2012-04-11 16:52:09
@Rex,我有同样的想法:-) – dhg 2012-04-11 16:55:39