Javascript 如何在返回单个对象时递归使用Array.prototype.find()?
我试图解决的更大问题是,考虑到这些数据:Javascript 如何在返回单个对象时递归使用Array.prototype.find()?,javascript,recursion,Javascript,Recursion,我试图解决的更大问题是,考虑到这些数据: var data = [ { id: 1 }, { id: 2 }, { id: 3 }, { id: 4, children: [ { id: 6 }, { id: 7, children: [ {id: 8 }, {id: 9 } ]} ]}, { id: 5 } ] 我想创建一个返回{id:id}的函数f
var data = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4, children: [
{ id: 6 },
{ id: 7, children: [
{id: 8 },
{id: 9 }
]}
]},
{ id: 5 }
]
我想创建一个返回{id:id}
的函数findById(data,id)
。例如,findById(data,8)
应该返回{id:8}
,而findById(data,4)
应该返回{id:4,子项:[……]}
为了实现这一点,我递归地使用了Array.prototype.find
,但是当return
不断地将对象混合在一起时遇到了问题。我的实现返回特定对象的路径
例如,当我使用findById(data,8)
时,它返回{id:8}
的路径:
{ id: 4, children: [ { id: 6 }, { id: 7, children: [ { id: 8}, { id: 9] } ] }
相反,我希望它只是返回
{ id: 8 }
实现(Node.js v4.0.0)
我将只使用常规循环和递归式搜索:
function findById(data, id) {
for(var i = 0; i < data.length; i++) {
if (data[i].id === id) {
return data[i];
} else if (data[i].children && data[i].children.length && typeof data[i].children === "object") {
findById(data[i].children, id);
}
}
}
//findById(data, 4) => Object {id: 4, children: Array[2]}
//findById(data, 8) => Object {id: 8}
函数findById(数据,id){
对于(变量i=0;i对象{id:4,子对象:数组[2]}
//findById(数据,8)=>对象{id:8}
您遇到的问题是查找的冒泡。如果在嵌套结构中找到id,回调将尝试返回元素(被解释为true)作为查找的值
find
方法对数组中的每个元素执行一次回调函数,直到找到回调返回真值的元素为止。[]
我建议不要使用find,而是使用递归样式进行搜索,如果找到,则使用短路
var data=[{id:1},{id:2},{id:3},{id:4,子项:[{id:6},{id:7,子项:[{id:8},{id:9}]},{id:5}];
函数findById(数据,id){
功能iter(a){
如果(a.id==id){
结果=a;
返回true;
}
返回数组.isArray(a.children)和&a.children.some(iter);
}
var结果;
数据部分(iter);
返回结果
}
log(findById(data,8))代码> 让我们考虑基于递归调用的实现:
function findById(tree, nodeId) {
for (let node of tree) {
if (node.id === nodeId) return node
if (node.children) {
let desiredNode = findById(node.children, nodeId)
if (desiredNode) return desiredNode
}
}
return false
}
用法
要根据解决方案简化图片
我对他的函数进行了修改,使其能够基于给定的动态属性递归地查找ID,并返回您想要查找的值或一个索引数组,以便随后递归地到达对象或属性
这类似于find
和findIndex
一起通过具有给定属性中对象嵌套数组的对象数组进行查找
findByIdRecursive(tree, nodeId, prop = '', byIndex = false, arr = []) {
for (let [index, node] of tree.entries()) {
if (node.id === nodeId) return byIndex ? [...arr, index] : node;
if (prop.length && node[prop].length) {
let found = this.findByIdRecursive(node[prop], nodeId, prop, byIndex, [
...arr,
index
]);
if (found) return found;
}
}
return false;
}
现在,您可以控制查找的属性和类型,并获得正确的结果。这可以通过reduce解决
const foundItem = data.reduce(findById(8), null)
function findById (id) {
const searchFunc = (found, item) => {
const children = item.children || []
return found || (item.id === id ? item : children.reduce(searchFunc, null))
}
return searchFunc
}
我知道这是一个老问题,但随着最近另一个答案的出现,我将在混合中加入另一个版本
我将把树遍历和测试从我们想要测试的实际谓词中分离出来。我相信这会使代码更加简洁
基于reduce
的解决方案可能如下所示:
const nestedFind=(pred)=>(xs)=>
减少(
(res,x)=>res?res:pred(x)?x:nestedFind(pred)(x.children | |[]),
未定义
)
常量findById=(testId)=>
nestedFind(({id})=>id==testId)
const data=[{id:1},{id:2},{id:3},{id:4,子项:[{id:6},{id:7,子项:[{id:8},{id:9}]},{id:5}]
console.log(findById(8)(数据))
console.log(findById(4)(数据))
console.log(findById(42)(数据))
.as控制台包装{min height:100%!important;top:0}
您可以与
constfindbyid=(a,id,p=“children”,u)=>
a、 长度?a、 find(o=>o.id==id)| | findById(a.flatMap(o=>o[p]| |[]),id):u;
常量树=[{id:1},{id:2},{id:3},{id:4,子项:[{id:6},{id:7,子项:[{id:8},{id:9}]},{id:5}];
console.log(findById(tree,9));//{id:9}
console.log(findById(tree,10));//未定义的
如果要使用数组.prototype.find
这是我选择的选项:
findById( my_big_array, id ) {
var result;
function recursiveFind( haystack_array, needle_id ) {
return haystack_array.find( element => {
if ( !Array.isArray( element ) ) {
if( element.id === needle_id ) {
result = element;
return true;
}
} else {
return recursiveFind( element, needle_id );
}
} );
}
recursiveFind( my_big_array, id );
return result;
}
您需要result变量,因为如果没有它,函数将返回包含结果的数组中的顶级元素,而不是对包含匹配id的深度嵌套对象的引用,这意味着您需要进一步过滤它
通过查看其他答案,我的方法似乎非常类似,但使用了find()
而不是some()
的解决方案,但更具可读性:
函数findById(数据、id、属性='children',defaultValue=null){
如果(!data.length){
返回默认值;
}
返回(
data.find(el=>el.id==id)||
芬德比德(
data.flatMap(el=>el[prop]| |[]),
身份证件
)
);
}
在我看来,如果您想按id递归搜索,最好使用如下算法:
函数findById(数据、id、属性='children',defaultValue=null){
用于(常量数据项){
如果(item.id==id){
退货项目;
}
if(Array.isArray(item[prop])&item[prop].length){
const元素=this.findById(项[prop],id,prop,defaultValue);
if(元素){
返回元素;
}
}
}
返回默认值;
}
findById(数据,2);
但我强烈建议使用更灵活的函数,它可以按任意键值对进行搜索:
函数findRecursive(数据、keyvalues、prop='children',defaultValue=null,_keys=null){
常量键=_键| |对象.键(键值);
用于(常量数据项){
if(key.every(key=>item[key]==keyvalues[key])){
退货项目;
}
if(Array.isArray(item[prop])&item[prop].length){
常数
const foundItem = data.reduce(findById(8), null)
function findById (id) {
const searchFunc = (found, item) => {
const children = item.children || []
return found || (item.id === id ? item : children.reduce(searchFunc, null))
}
return searchFunc
}
findById( my_big_array, id ) {
var result;
function recursiveFind( haystack_array, needle_id ) {
return haystack_array.find( element => {
if ( !Array.isArray( element ) ) {
if( element.id === needle_id ) {
result = element;
return true;
}
} else {
return recursiveFind( element, needle_id );
}
} );
}
recursiveFind( my_big_array, id );
return result;
}