繁体   English   中英

Javascript:找到树中元素的所有父母

[英]Javascript: Find all parents for element in tree

我有对象树,我找不到具体对象id的所有父母。 想象一下,我需要为id = 5的对象的每个父节点添加一些新字段。有人可以通过树的递归循环来帮助

 var tree = { id: 1, children: [ { id: 3, parentId: 1, children: [ { id: 5, parentId: 3, children: [] } ] } ] } console.log(searchTree (tree, 5)); function searchTree (tree, nodeId){ for (let i = 0; i < tree.length; i++){ if (tree[i].id == nodeId) { // it's parent console.log(tree[i].id); tree[i].newField = true; if (tree[i].parentId != null) { searchTree(tree, tree[i].parentId); } } } } 

数据构造函数

人们需要停止写这样的数据:

const tree = 
  { id: 1, parentId: null, children:
    [ { id: 3, parentId: 1, children:
      [ { id: 5, parentId: 3, children: [] } ] } ] }

并使用数据构造函数开始编写数据

 // "Node" data constructor const Node = (id, parentId = null, children = Children ()) => ({ id, parentId, children }) // "Children" data constructor const Children = (...values) => values // write compound data const tree = Node (1, null, Children (Node (3, 1, Children (Node (5, 3))))) console.log (tree) // { id: 1, parentId: null, children: [ { id: 3, parentId: 1, children: [ { id: 5, parentId: 3, children: [] } ] } ] } 

这允许您将您的想法与诸如{} ,或[]甚至x => ...用于包含数据的详细信息分开。 我会更进一步,创建一个带有保证tag字段的统一接口 - 以便以后可以将其与其他通用数据区分开来

堆栈片段在下面的程序中对输出进行屠宰是完美的。 不要紧 ,什么数据看起来在打印时一样- 重要的是很容易为我们人类在我们的程序中读/写,并很容易为我们的程序读取 / 写入

当/如果你需要它以特定的格式/形状, 然后将其强制成那个形状; 直到那一点,保持它很好,易于使用

 const Node = (id, parentId = null, children = Children ()) => ({ tag: Node, id, parentId, children }) const Children = (...values) => ({ tag: Children, values }) // write compound data const tree = Node (1, null, Children (Node (3, 1, Children (Node (5, 3))))) console.log (tree) // { ... really ugly output, but who cares !.. } 


让我们来搜索

我们可以使用简单的loop辅助函数编写search - 但请注意您没有看到的内容; 几乎没有逻辑(使用单个三元表达式); 没有像i++这样的for / while或者手动迭代器递增的命令式构造; 不使用像push / unshift这样的mutator或者像.forEach这样的.forEach函数; 没有毫无意义的.length属性检查或直接索引读取使用[i]式查找 - 它只是函数和调用; 我们不必担心任何其他噪音

 const Node = (id, parentId = null, children = Children ()) => ({ tag: Node, id, parentId, children }) const Children = (...values) => ({ tag: Children, values }) const tree = Node (1, null, Children (Node (3, 1, Children (Node (5, 3))))) const search = (id, tree = null) => { const loop = (path, node) => node.id === id ? [path] : node.children.values.reduce ((acc, child) => acc.concat (loop ([...path, node], child)), []) return loop ([], tree) } const paths = search (5, tree) console.log (paths.map (path => path.map (node => node.id))) // [ 1, 3 ] 

所以search返回一个路径数组 ,其中每个路径都是一个节点数组 - 为什么会这样呢? 如果ID为X出现在树中的多个位置,则将返回子项的所有路径

 const Node = (id, parentId = null, children = Children ()) => ({ tag: Node, id, parentId, children }) const Children = (...values) => ({ tag: Children, values }) const tree = Node (0, null, Children ( Node (1, 0, Children (Node (4, 1))), Node (2, 0, Children (Node (4, 2))), Node (3, 0, Children (Node (4, 3))))) const search = (id, tree = null) => { const loop = (path, node) => node.id === id ? [path] : node.children.values.reduce ((acc, child) => acc.concat (loop ([...path, node], child)), []) return loop ([], tree) } const paths = search (4, tree) console.log (paths.map (path => path.map (node => node.id))) // [ [ 0, 1 ], // [ 0, 2 ], // [ 0, 3 ] ] 


你不小心写了monad列表

列表monad编码模糊计算的想法 - 即,可以返回一个或多个结果的计算的想法。 让我们对我们的程序做一个小改动 - 这是有利的,因为List是通用的,现在可以用在我们程序中的其他地方,这种计算是必不可少的

如果你喜欢这个解决方案,你可能会喜欢阅读我讨论monad列表的其他答案

 const List = (xs = []) => ({ tag: List, value: xs, chain: f => List (xs.reduce ((acc, x) => acc.concat (f (x) .value), [])) }) const Node = (id, parentId = null, children = Children ()) => ({ tag: Node, id, parentId, children }) const Children = (...values) => List (values) const search = (id, tree = null) => { const loop = (path, node) => node.id === id ? List ([path]) : node.children.chain (child => loop ([...path, node], child)) return loop ([], tree) .value } const tree = Node (0, null, Children ( Node (1, 0, Children (Node (4, 1))), Node (2, 0, Children (Node (4, 2))), Node (3, 0, Children (Node (4, 3))))) const paths = search (4, tree) console.log (paths.map (path => path.map (node => node.id))) // [ [ 0, 1 ], // [ 0, 2 ], // [ 0, 3 ] ] 

最简单的解决方案是将树形结构向下展平,这样您就可以查找ID并执行简单的while循环

 var tree = { id: 1, children: [ { id: 3, parentId: 1, children: [ { id: 5, parentId: 3, children: [] } ] } ] } // We will flatten it down to an object that just holds the id with the object var lookup = {} function mapIt (node) { lookup[node.id] = node; //recursive on all the children node.children && node.children.forEach(mapIt); } mapIt(tree) // This takes a node and loops over the lookup hash to get all of the ancestors function findAncestors (nodeId) { var ancestors = [] var parentId = lookup[nodeId] && lookup[nodeId].parentId while(parentId !== undefined) { ancestors.unshift(parentId) parentId = lookup[parentId] && lookup[parentId].parentId } return ancestors; } // Let us see if it works console.log("5: ", findAncestors(5)) 

这是一个工作递归函数的例子。

玩了一会儿,你应该是金色的

 var tree = { id: 1, children: [{ id: 3, parentId: 1, children: [{ id: 5, parentId: 3, children: [] }] }] } function mapit(node, parent = null) { node.parent = parent; if (node.children.length > 0) { for (var i = 0; i < node.children.length; i++) { var child = node.children[i]; mapit(child, node); } } } mapit(tree); console.log(tree); 

递归函数并不困难。 请记住,如果不满足参数,则将新级别传递给函数。

 var tree = [{ id: 1, children: [{ id: 3, parentId: 1, children: [{ id: 5, parentId: 3, children: [{ id: 6, parentId: 5, children: [{ id: 5, parentId: 3, children: [] }] }] }] }] }]; //wrap first obj in an array too. searchTree(tree, 5); console.log(tree); function searchTree(tree, nodeId) { for (let i = 0; i < tree.length; i++) { if (tree[i].id == nodeId) { tree[i]; //id found, now add what you need. tree[i].newField = "added"; }//if child has children of its own, continu digging. if (tree[i].children != null && tree[i].children.length > 0) { searchTree(tree[i].children, nodeId); //pass the original nodeId and if children are present pass the children array to the function. } } } 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM