【问题标题】:Search for children with id in javascript在 javascript 中搜索具有 id 的孩子
【发布时间】:2019-04-12 04:41:54
【问题描述】:

我有一个这样的数组:

[
    {
        id: "1233",
        parentId: "5436"
    },
    {
        id: "5436",
        parentId: "5664"
    },
    ...
]

它是一棵树的代表,有孩子和父母。所以它实际上是一个对象数组,每个对象都有一个 id 和一个父 id。

我想创建一个函数,最好使用 ES6 搜索给定 id 的元素的所有子元素(不仅是直接子元素,还包括子元素的子元素)。

或者,如果有一个函数可以将这个数组转换成更方便的形式,比如带有 id 和 children 数组的对象数组。

我使用了以下功能进行搜索:

function searchForChildren(parentId, tree) {
const children = [];
tree.forEach(element => {
    if (element.parentUid === parentId) {
        children.push(element);
    }
});
for (const child of children) {
    const childrenTemp = searchForChildren(child.id, tree);
    children.concat(childrenTemp);
}
return children;
}

示例数据如下:

 0: {id: "7020441", parentUid: "2442074"}
 1: {id: "7020438", parentUid: "2442077"}
 2: {id: "7020435", parentUid: "2442079"}
 3: {id: "7020437", parentUid: "2442079"}
 4: {id: "7013749", parentUid: "2442086"}
 5: {id: "7013750", parentUid: "2442086"}
 6: {id: "7013752", parentUid: "2442086"}
 7: {id: "7013753", parentUid: "2442086"}
 8: {id: "7013751", parentUid: "2442086"}
 9: {id: "7013746", parentUid: "2442089"}
 10: {id: "7013747", parentUid: "2442089"}
 11: {id: "7013765", parentUid: "2442092"}
 12: {id: "7013767", parentUid: "2442092"}
 13: {id: "7013768", parentUid: "2442092"}
 14: {id: "7013765", parentUid: "2442092"}
 15: {id: "7013767", parentUid: "2442092"}
 16: {id: "7013768", parentUid: "2442092"}
 17: {id: "7013765", parentUid: "2442092"}
 18: {id: "7013767", parentUid: "2442092"}
 19: {id: "7013768", parentUid: "2442092"}
 20: {id: "7013765", parentUid: "2442092"}
 21: {id: "7013767", parentUid: "2442092"}
 22: {id: "7013768", parentUid: "2442092"}
 23: {id: "7013765", parentUid: "2442092"}
 24: {id: "7013767", parentUid: "2442092"}
 25: {id: "7013768", parentUid: "2442092"}
 26: {id: "7013765", parentUid: "2442092"}
 27: {id: "7013767", parentUid: "2442092"}
 28: {id: "7013768", parentUid: "2442092"}
 29: {id: "7013765", parentUid: "2442092"}
 30: {id: "7013767", parentUid: "2442092"}
 31: {id: "7013768", parentUid: "2442092"}
 32: {id: "7013765", parentUid: "2442092"}
 33: {id: "7013767", parentUid: "2442092"}
 34: {id: "7013768", parentUid: "2442092"}
 35: {id: "7013765", parentUid: "2442092"}
 36: {id: "7013767", parentUid: "2442092"}
 37: {id: "7013768", parentUid: "2442092"}
 38: {id: "7013765", parentUid: "2442092"}
 39: {id: "7013767", parentUid: "2442092"}
 40: {id: "7013768", parentUid: "2442092"}
 41: {id: "7013765", parentUid: "2442092"}
 42: {id: "7013767", parentUid: "2442092"}
 43: {id: "7013768", parentUid: "2442092"}
 44: {id: "7013765", parentUid: "2442092"}
 45: {id: "7013767", parentUid: "2442092"}
 46: {id: "7013768", parentUid: "2442092"}
 47: {id: "2442074", parentUid: ""}
 48: {id: "2442075", parentUid: "2442074"}
 49: {id: "2442076", parentUid: "2442075"}
 50: {id: "2442077", parentUid: "2442076"}
 51: {id: "2442078", parentUid: "2442076"}
 52: {id: "2442079", parentUid: "2442075"}
 53: {id: "2442080", parentUid: "2442075"}
 54: {id: "2442081", parentUid: "2442075"}
 55: {id: "2442082", parentUid: "2442074"}
 56: {id: "2442083", parentUid: "2442074"}
 57: {id: "2442084", parentUid: "2442074"}
 58: {id: "2442085", parentUid: "2442084"}
 59: {id: "2442086", parentUid: "2442084"}
 60: {id: "2442087", parentUid: "2442084"}
 61: {id: "2442088", parentUid: "2442084"}
 62: {id: "2442089", parentUid: "2442088"}
 63: {id: "2442090", parentUid: "2442074"}
 64: {id: "2442091", parentUid: "2442090"}
 65: {id: "2442092", parentUid: "2442091"}
 66: {id: "2442092", parentUid: "2442091"}
 67: {id: "2442092", parentUid: "2442091"}
 68: {id: "2442091", parentUid: "2442090"}
 69: {id: "2442092", parentUid: "2442091"}
 70: {id: "2442092", parentUid: "2442091"}
 71: {id: "2442092", parentUid: "2442091"}
 72: {id: "2442091", parentUid: "2442090"}
 73: {id: "2442092", parentUid: "2442091"}
 74: {id: "2442092", parentUid: "2442091"}
 75: {id: "2442092", parentUid: "2442091"}
 76: {id: "2442091", parentUid: "2442090"}
 77: {id: "2442092", parentUid: "2442091"}
 78: {id: "2442092", parentUid: "2442091"}
 79: {id: "2442092", parentUid: "2442091"}
 80: {id: "2442093", parentUid: "2442090"}
 81: {id: "2442094", parentUid: "2442074"}
 82: {id: "2442095", parentUid: "2442074"}

【问题讨论】:

  • 看来您这里有一个平面列表,而不是嵌套列表。如果是这种情况,如果您知道id 的下限和上限,请进行线性搜索或二分搜索。
  • 你能把这个列表分享给至少几个对象吗
  • 向我们展示您的尝试。 Stackoverflow 不是免费的代码编写服务。此处的目标是帮助修复您的代码。展示您的尝试将为您提供更高水平的帮助,而不是期望其他人从头开始做这一切
  • 请编辑问题而不是将代码放入您的 cmets

标签: javascript algorithm search ecmascript-6


【解决方案1】:

我会创建一个索引来将搜索复杂度从 O(n) 降低到 O(1)。对于大型数据集,这将在执行时间上产生很大差异。

var index = {}, index_parent = {}, obj;
for (var i in myArray) {
  obj = myArray[i];
  index[obj.id] = obj;

  if (index_parent.hasOwnProperty(obj.parentUid)) {

    index_parent[obj.parentUid].push(obj.id);
  } else {
    index_parent[obj.parentUid] = [obj.id];
  }
}

然后做呼吸先搜索

function getChildren_BFS (id_parent) {
  var out = [], qu = [], node, children;
  out.push(index[id_parent]); // this can be commented out if you don't need the root

  qu.push(id_parent);

  for (var current = 0; qu.length > current; ) {

    node = qu[current++];

    children = index_parent[node];

    if (children) {
      qu = qu.concat(children);

      children.forEach((e) => {out.push(index[e]);});
    }
  }

  return out;
}

var myArray = [{id: "7020441", parentUid: "2442074"}
,{id: "7020438", parentUid: "2442077"}
,{id: "7020435", parentUid: "2442079"}
,{id: "7020437", parentUid: "2442079"}
,{id: "7013749", parentUid: "2442086"}
,{id: "7013750", parentUid: "2442086"}
,{id: "7013752", parentUid: "2442086"}
,{id: "7013753", parentUid: "2442086"}
,{id: "7013751", parentUid: "2442086"}
,{id: "7013746", parentUid: "2442089"}
,{id: "7013747", parentUid: "2442089"}
,{id: "7013765", parentUid: "2442092"}
,{id: "7013767", parentUid: "2442092"}
,{id: "7013768", parentUid: "2442092"}
,{id: "2442074", parentUid: ""}
,{id: "2442075", parentUid: "2442074"}
,{id: "2442076", parentUid: "2442075"}
,{id: "2442077", parentUid: "2442076"}
,{id: "2442078", parentUid: "2442076"}
,{id: "2442079", parentUid: "2442075"}
,{id: "2442080", parentUid: "2442075"}
,{id: "2442081", parentUid: "2442075"}
,{id: "2442082", parentUid: "2442074"}
,{id: "2442083", parentUid: "2442074"}
,{id: "2442084", parentUid: "2442074"}
,{id: "2442085", parentUid: "2442084"}
,{id: "2442086", parentUid: "2442084"}
,{id: "2442087", parentUid: "2442084"}
,{id: "2442088", parentUid: "2442084"}
,{id: "2442089", parentUid: "2442088"}
,{id: "2442090", parentUid: "2442074"}
,{id: "2442092", parentUid: "2442091"}
,{id: "2442091", parentUid: "2442090"}
,{id: "2442093", parentUid: "2442090"}
,{id: "2442094", parentUid: "2442074"}
,{id: "2442095", parentUid: "2442074"}];

var index = {}, index_parent = {}, obj;
myArray.forEach((obj) => {

  index[obj.id] = obj;

  if (index_parent.hasOwnProperty(obj.parentUid)) {

    index_parent[obj.parentUid].push(obj.id);
  } else {
    index_parent[obj.parentUid] = [obj.id];
  }
});

console.log( getChildren_BFS("2442084") );
console.log( getChildren_BFS("2442074") );

在内存占用方面需要改进。

编辑: 这是使用深度优先搜索的相同 getChildren,只需更改堆栈的队列即可。

function getChildren_DFS (id_parent) {
  var out = [], stack = [], node, children;
  out.push(index[id_parent]); // this can be commented out if you don't need the root

  stack.push(id_parent);

  while (stack.length > 0) {

    node = stack.pop();

    children = index_parent[node];

    if (children) {
      children.forEach((e) => {stack.push(e);});

      children.forEach((e) => {out.push(index[e]);});
    }
  }

  return out;
}

【讨论】:

  • 使用索引是个好主意,它实际上解决了我的两个问题,找到所有孩子并将数组转换为更方便的形式。但是对于想要一眨眼就明白发生了什么的人来说,代码很难理解。
  • @TheodosiosAsvestopoulos 我添加了 DFS 版本的搜索。
【解决方案2】:

您使用递归的想法是正确的。您唯一的错误是您使用的是children.concat(childrenTemp),它对原始数组没有任何作用。而是使用children.push(...childrenTemp)

这是固定版本:

const data = [{
    id: "2442086",
    parentUid: "2442074"
  },
  {
    id: "7020438",
    parentUid: "2442077"
  },
  {
    id: "7020435",
    parentUid: "2442079"
  },
  {
    id: "7020437",
    parentUid: "2442079"
  },
  {
    id: "2442092",
    parentUid: "2442086"
  },
  {
    id: "7013750",
    parentUid: "2442086"
  },
  {
    id: "7013752",
    parentUid: "2442086"
  },
  {
    id: "7013753",
    parentUid: "2442086"
  },
  {
    id: "7013751",
    parentUid: "2442086"
  },
  {
    id: "7013746",
    parentUid: "2442089"
  },
  {
    id: "7013747",
    parentUid: "2442089"
  },
  {
    id: "7013765",
    parentUid: "2442092"
  },
  {
    id: "7013767",
    parentUid: "2442092"
  },
  {
    id: "7013768",
    parentUid: "2442092"
  },
  {
    id: "7013765",
    parentUid: "2442092"
  },
  {
    id: "7013767",
    parentUid: "2442092"
  },
  {
    id: "7013768",
    parentUid: "2442092"
  },
  {
    id: "7013765",
    parentUid: "2442092"
  },
  {
    id: "7013767",
    parentUid: "2442092"
  },
  {
    id: "7013768",
    parentUid: "2442092"
  },
  {
    id: "7013765",
    parentUid: "2442092"
  },
  {
    id: "7013767",
    parentUid: "2442092"
  },
  {
    id: "7013768",
    parentUid: "2442092"
  },
  {
    id: "7013765",
    parentUid: "2442092"
  },
  {
    id: "7013767",
    parentUid: "2442092"
  },
  {
    id: "7013768",
    parentUid: "2442092"
  },
  {
    id: "7013765",
    parentUid: "2442092"
  },
  {
    id: "7013767",
    parentUid: "2442092"
  }
];


function searchForChildren(parentId, tree) {
  const children = [];
  tree.forEach(element => {
    if (element.parentUid === parentId) {
      children.push(element);
    }
  });
  for (const child of children) {
    const childrenTemp = searchForChildren(child.id, tree);
    children.push(...childrenTemp);
  }
  return children;
}

console.log(searchForChildren("2442092", data));
console.log(searchForChildren("2442086", data));

来自docs

concat() 方法用于合并两个或多个数组。这种方法 不会改变现有数组,而是返回一个新数组。

【讨论】:

  • 速度很慢,效率很低。
猜你喜欢
  • 2019-04-18
  • 1970-01-01
  • 2016-04-09
  • 1970-01-01
  • 2011-05-09
  • 1970-01-01
  • 2019-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多