我有一個函數,計算一些簡單的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