迭代和搜索 n 维嵌套数组中的元素

Iterating and searching for element in n-dimensional nested array

提问人:gyan mishra 提问时间:1/30/2023 更新时间:1/30/2023 访问量:89

问:

下面是一个数组

    id: 0,
    parent: 'p1',
    children: [
        {
            id: 1,
            parent: 'p2',
            children: [
                {
                    id: 3,
                    parent: 'p4',
                    children: []
                },
            ]
        },
        {
            id: 2,
            parent: 'p3',
            children: [
                {
                    id: 4,
                    parent: 'p5',
                    children: []
                },
            ]
        }
    ]
}

我正在尝试根据 id 值搜索一个元素,并将其从数组中删除并 将其替换为空数组

例如,如果我通过

let childTobeReplaced = childrenCollector(4, treeData.children);

结果必须是

{
    id: 0,
    parent: 'p1',
    children: [
        {
            id: 1,
            parent: 'p2',
            children: [
                {
                    id: 3,
                    parent: 'p4',
                    children: []
                },
            ]
        },
        {
            id: 2,
            parent: 'p3',
            children: []
        }
    ]
}

childTobeReplaced 必须等于

{
    id: 4,
    parent: 'p5',
    children: []
}

我实施的解决方案如下

function childrenCollector(sourceId, nestedarray) {
    for (let index = 0; index < nestedarray.length; index++) {
        console.log(nestedarray[index].id)
        if (nestedarray[index].id === sourceId) {
            let childArray = nestedarray[index];
            nestedarray[index] = []
            return childArray;
        }
        if (nestedarray[index].children.length > 0) {
            return childrenCollector(sourceId, nestedarray[index].children);
        }else{

        }
    }
}

在这种情况下,我能够遍历 id 1 和 id 3,但无法找到其余的元素 .有人可以给我一些指导吗?

JavaScript 多维 结构 数据操作 数组算法

评论


答:

1赞 trincot 1/30/2023 #1

当对象具有子对象时,您的函数将在循环的第一次迭代中,这意味着不会检查数组的其余部分。那不是你想要的。仅当您确定递归调用找到了该元素时,才退出循环。return

其次,不是从中删除索引。它只是将对该索引处对象的引用替换为对空数组的引用。nestedarray[index] = []nestedarray

下面是一个可能的实现:

function childrenCollector(sourceId, nestedArray) {
    const i = nestedArray.findIndex(({id}) => id === sourceId);
    let found;
    if (i > -1) [found] = nestedArray.splice(i, 1)
    else nestedArray.some(({children}) => 
         found = childrenCollector(sourceId, children)
    );
    return found;
}

// Example data from the question
const treeData = {id: 0,parent: 'p1',children: [{id: 1,parent: 'p2',children: [{id: 3,parent: 'p4',children: []},]},{id: 2,parent: 'p3',children: [{id: 4,parent: 'p5',children: []},]}]};

const childTobeReplaced = childrenCollector(4, treeData.children);
console.log(childTobeReplaced);
console.log(treeData);

解释:

使用代码尝试在给定的数组中找到 。回调函数使用解构来让 be 迭代对象的属性。当回调函数返回 true 时,迭代停止,并将相应的索引分配给 。如果没有匹配项,将设置为 -1。findIndexididfindIndexii

如果存在匹配项,将从该索引处的数组中提取该元素,并将返回已删除元素的数组。由于只有一个删除的元素,因此该数组将只有一个元素。这个元素被赋值给 ,同样使用解构赋值。splicefound

如果没有匹配项,则再次迭代数组,但现在进行递归调用。对于此迭代,它也将在成功后立即停止迭代。在每次迭代中,设置为递归调用的结果。一旦这是一个对象(表示找到了某些东西),循环就会退出。somefound

无论哪种情况,都将返回对象(如果有),否则 .foundundefined

评论

0赞 gyan mishra 1/30/2023
此返回的元素的 ID 为 2 而不是 4
0赞 trincot 1/30/2023
明白了。现在已经解决了。
0赞 gyan mishra 1/30/2023
您能否解释一下您的方法,这将非常有帮助
1赞 trincot 1/30/2023
添加了解释。
0赞 gog 1/30/2023 #2

下面是一个简单的不可变解决方案:

let remove = (node, id) => ({
    ...node,
    children: node.children
        .filter(child => child.id !== id)
        .map(child => remove(child, id))
})

给定一个节点,它会删除具有给定 ID 的子节点,然后对每个剩余的子节点应用相同的过程。

评论

0赞 trincot 1/30/2023
请注意,请求者希望函数返回已删除的节点。