首页 > 解决方案 > 遍历嵌套数组,通过id找到特定的叶子节点,并将其移除

问题描述

JSFiddle

我有一个最多有 6 个级别的嵌套数组。第 6 层称为gls,它保存gl数据库中 s 的对象。我需要做的是找到一个特定的gl并将其从整个阵列中删除。我能够找到具有以下功能的特定元素;

const removeFromData = function(nodes, id) {
  return nodes.some((node) => {
    if (node.gls) {
      node.gls.forEach((gl) => {
        if (gl.id === id) {
          console.log(gl, id);
        }
      });
    } else if (node.children) {
      return removeFromData(node.children, id);
    }
  });
}

但是,我正在努力将其从data阵列中实际删除。尝试通过执行来获取索引data.indexOf(gl)显然会返回-1,因为它不会搜索嵌套元素。实现这一目标的最佳方法是什么?

const id = 1000;

const data = [{
    "id": 1, "name": "Node 1", "children": [{
      "id": 2, "name": "Node 1.1", "children": [{
        "id": 4, "name": "Node 1.1.1", "leaf": true, "children": [], "gls": [{
          "id": 1000, "name": "GL1", "code": "0100"
        }, {
          "id": 1001, "name": "GL2", "code": "0200"
        }]
      }, {
        "id": 5, "name": "Node 1.1.2", "leaf": true, "children": [], "gls": [{
          "id": 2000, "name": "GL3", "code": "0300"
        }, {
          "id": 2001, "name": "GL4", "code": "0400"
        }]
      }]
    }, {
      "id": 3, "name": "Node 1.2", "children": [{
        "id": 6, "name": "Node 1.2.1", "leaf": true, "children": [], "gls": [{
          "id": 3000, "name": "GL5", "code": "0500"
        }, {
          "id": 3001, "name": "GL6", "code": "0600"
        }]
      }]
    }]
  },
  {
    "id": 7, "name": "Node 2", "children": [{
      "id": 8, "name": "Node 2.1", "children": [{
        "id": 9, "name": "Node 2.1.1", "leaf": true, "children": [], "gls": [{
          "id": 4000, "name": "GL7", "code": "0700"
        }, {
          "id": 4001, "name": "GL8", "code": "0800"
        }]
      }]
    }]
  }
];


let removeFromData = function(nodes, id) {
  return nodes.some((node) => {
    if (node.gls) {
      node.gls.forEach((gl) => {
        if (gl.id === id) {
          document.querySelector('#target').innerText = `found ${gl.name}, ${gl.id} with needle ${id}`;
        }
      });
    } else if (node.children) {
      return removeFromData(node.children, id);
    }
  });
}

removeFromData(data, id);
<p id="target"></p>

标签: javascriptarraysrecursion

解决方案


forEach将三个参数传递给回调,其中第二个是被访问条目的索引。因此,您可以使用该索引splice(如果您想就地修改):

const removeFromData = function(nodes, id) {
  return nodes.some((node) => {
    if (node.gls) {
      node.gls.forEach((gl, index) => {
// -----------------------^^^^^^^
        if (gl.id === id) {
          //console.log(gl, id);
          node.gls.splice(index, 1); // <=== Removes the entry
        }
      });
    } else if (node.children) {
      return removeFromData(node.children, id);
    }
  });
}

我注意到您正在使用some,这表明您希望在找到该条目时停止,并且可能还返回一个指示成功/失败的标志。如果是这样,我会使用而some不是搜索或可能使用。与:forEachnodes.glsfindIndexsome

const removeFromData = function(nodes, id) {
  return nodes.some((node) => {
    if (node.gls) {
      return node.gls.some((gl, index) => {
        if (gl.id === id) {
          //console.log(gl, id);
          node.gls.splice(index, 1); // <=== Removes the entry
          return true;
        }
      });
    } else if (node.children) {
      return removeFromData(node.children, id);
    }
  });
}

findIndex

const removeFromData = function(nodes, id) {
  return nodes.some((node) => {
    if (node.gls) {
      const index = node.gls.findIndex((gl) => {
        return gl.id === id;
      });
      if (index === -1) {
        return false;
      }
      node.gls.splice(index, 1);
      return true;
    } else if (node.children) {
      return removeFromData(node.children, id);
    }
  });
}

推荐阅读