与数组对象一起使用

我有一个可以包含相同对象types的子对象的数组,像这样:

var exampleArray = [ { alias: 'alias1', children: [ { alias: 'child1' }, { alias: 'child2', children: [ { alias: 'child4' }, { alias: 'child5' } ] }, { alias: 'child3' } ] }, { alias: 'alias2' }, { alias: 'alias3', children: [ { alias: 'child6' }, { alias: 'child7' } ] } ]; 

基础对象具有其他属性,但对于手头的问题并不重要。 现在,让我们假设对象可以是:

 { alias: 'string', children: [] } 

孩子是可选的。

我正在寻找最好的方法/最快的方法来pipe理这样的对象的东西。 我已经创build了一些recursion方法来完成我想要的一些事情,但是我想知道是否有更好的方法来完成以下任务:

  1. hasAlias(arr,别名) – 我需要确定整个对象是否包含具有给定别名的任何对象。

目前,我是recursion地做这个,但是考虑到这个数组可以有限地增长,recursion方法最终会达到栈限制。

  1. getParent(arr,别名) – 我需要能够获得包含具有给定别名的元素的父代。 鉴于别名对于整个数组是独一无二的,永远不会有两个相同的别名。 我再一次recursion地做到这一点,但我想find更好的方法来做到这一点。

  2. deleteObject(arr,别名) – 我不确定如何完成这一个目前。 我需要能够传递一个数组和一个别名,并将该对象(及其所有子对象)从给定的数组中移除。 我开始了这样做的recursion方法,但停下来,决定在这里发表。

我正在使用Node.js,并有更快的方法处理lodash。 我还是比较新的JavaScript,所以我不确定是否有更好的方法来处理像这样的大规模数组。

在不支持recursion的FORTRAN时代,通过改变数据集来模拟“recursion”级别,达到了类似的效果。 将这个原则应用到示例对象结构中,可以按如下方式编写通过其“别名”(名称或id由另一个词)查找对象的函数:

 function findAlias( parent, alias) // parent object, alias value string { function frame( parent) { return {parent: parent, children: parent.children, index: 0, length: parent.children.length}; } var stack, tos, child, children, i; stack = []; if( parent.children) stack.push( frame( parent)); search: while( stack.length) { tos = stack.pop(); // top of generation stack children = tos.children; for( i = tos.index; i < tos.length; ++i) { child = children[i]; if( child.alias == alias) { return { parent: tos.parent, child: child, childIndex: i} } if( child.children) { tos.index = i + 1; stack.push(tos); // put it back stack.push( frame(child)); continue search; } } } return null; } 

简而言之,最终会创build一堆小型的数据对象,这些数据对象在同一个函数中被推送和popup,而不是进行recursion调用。 上面的例子返回parent对象和child对象的对象。 子值是具有提供的别名属性的值,而父对象是在其children数组中具有children元素的值。

如果找不到别名,则返回null,因此可用于hasAliasfunction。 如果它不返回null,它将执行getParentfunction。 但是您必须创build一个根节点:

 // create a rootnode var rootNode = { alias: "root", children: exampleArray}; var found = findAlias(rootNode, "alias3"); if( found) { console.log("%s is a child of %s, childIndex = %s", found.child.alias, found.parent.alias, found.childIndex); } else console.log("not found"); 

[编辑:添加childIndex来search返回对象,更新testing示例代码,添加结论。]

结论

如果支持树形漫游应用程序,则使用recursion函数调用在自logging代码和可维护性方面是有意义的。 如果在递减压力testing下可以显示减less服务器负载有显着的好处,但是需要合理的文档,则非recursion变化可能会付出代价。

无论内部编码如何,通过减less已经执行的树形遍历的总数,树形漫步function返回具有父,子和子索引值的细节的对象可能有助于整体程序效率:

  • search返回值的真实性替代hasAlias函数
  • 可以传递来自search的返回对象来更新,删除或插入函数,而不需要在每个函数中进行重复的树search。

保证最快的方式显然是有的

 - an index for the aliases (thats actually a unique id) - have a parent backlink on each child item (if it has a parent) 

你仰望id指数

 var index = {} (function build(parent) { index[parent.alias] = parent; (parent.children || []).forEach( item => { item.parent = parent build(item) }) })(objectRoot) function hasAlias(alias) { return alias in index } function getAlias(alias) { return index[alias] } function getParent(alias) { return index[alias] && index[alias].parent} 

删除一个别名意味着将它和它的孩子从索引中删除,并从父索引中删除

 function deleteAlias(alias) { function deleteFromIndex(item) { delete index[item.alias] (item.children || []).forEach(deleteFromIndex) } var item = index[alias] item.parent.children.splice(item.parent.children.indexOf(item)) deleteFromIndex(item) } 

我可能会略微不同地接近你的主要数组,并保持它作为一个平面数组引用其他项目,而不是完全合并它们。

 var flat = [ { alias : "str1", children : [ flat[1], flat[2] ], parent : null }, { alias : "str1", children : [], parent : flat[0] }, { alias : "str1", children : [], parent : flat[0] } ] 

这是一种“ 链接列表 ”的方法。 有链接列表的优点和缺点,但您可以快速迭代所有项目。