如何创建一个函数来从嵌套的 object 中检索所有 children 的 ID

How to create a function to retrieve all children's id from a nested object

我想检索特定组的所有 child 个 ID,可以是深度嵌套,也可以不是深度嵌套。

这是一个示例 json:

[
      {
        id: 1,
        name: 'Desjardins Group 1',
        children: [
          { id: 2, name: 'Analysts', children: [] },
          { id: 3, name: 'Administration', children: [] }
        ]
      },
      {
        id: 4,
        name: 'Desjardins Group 2',
        children: [
          { id: 5, name: 'Consultants1', children: [] },
          {
            id: 6,
            name: 'Consultant2',
            children: [
              {
                id: 7, name: 'Interns', children: [
                  { id: 8, name: 'subInterns1', children: [] },
                  { id: 9, name: 'subInterns2', children: [] },
                  { id: 10, name: 'subInterns3', children: [] }
                ]
              }
            ]
          }
        ]
      }
    ]

我正在尝试创建一个函数,它带有一个带有参数的 ID,并且 return 所有 child 个 ID。 例如:getChildGroups(6) 会 return 7、8、9 和 10。

我想递归函数和过滤器是可行的方法,但我找不到合适的例子。

将您的问题分成两个较小的问题可能是个好主意:

  1. 找到一组嵌套在图中某处的ID x
  2. 给定一个节点,return递归其所有子节点ID

第一个问题的解决方案可能如下所示:

function findGroupId(o, id) {
    if (o.id == id) {
        // We found it!
        return o;
    }

    if (Array.isArray(o)) {
        // If we start with a list of objects, pretend it is the root node
        o = {children: o}
    }

    let results = [];
    for (let c of o.children) {
        // recursively call this function again
        results.push(findGroupId(c, id))
    }

    // return the first matching node
    return results.filter(r => r !== undefined)[0];
}

第二个问题:

function getAllChildrenIDs(o) {
    if (o.children === undefined)
        return [];

    let ids = [];

    for (c of o.children) {
        ids.push(c.id);
        // recursively call this function again
        for (id of getAllChildrenIDs(c))
            ids.push(id);
    }
    return ids;
}

如果我们把它们放在一起:

let example = [{
    id: 1,
    name: 'Desjardins Group 1',
    children: [{
        id: 2,
        name: 'Analysts',
        children: []
      },
      {
        id: 3,
        name: 'Administration',
        children: []
      }
    ]
  },
  {
    id: 4,
    name: 'Desjardins Group 2',
    children: [{
        id: 5,
        name: 'Consultants1',
        children: []
      },
      {
        id: 6,
        name: 'Consultant2',
        children: [{
          id: 7,
          name: 'Interns',
          children: [{
              id: 8,
              name: 'subInterns1',
              children: []
            },
            {
              id: 9,
              name: 'subInterns2',
              children: []
            },
            {
              id: 10,
              name: 'subInterns3',
              children: []
            }
          ]
        }]
      }
    ]
  }
];

function findGroupId(o, id) {
  if (o.id == id) {
    return o;
  }

  if (Array.isArray(o)) {
    o = {
      children: o
    }
  }

  let results = [];
  for (let c of o.children) {
    results.push(findGroupId(c, id))
  }

  return results.filter(r => r !== undefined)[0];
}

function getAllChildrenIDs(o) {
  if (o.children === undefined)
    return [];
  let ids = [];
  for (c of o.children) {
    ids.push(c.id);
    for (id of getAllChildrenIDs(c))
      ids.push(id);
  }
  return ids;
}

console.log(getAllChildrenIDs(findGroupId(example, 6)))

这是 Johann Bauer 回答的简化版本。

第一个函数只是找到与给定ID匹配的第一个节点,不需要任何数据积累:

function findNode(data, id) {
    if (!Array.isArray(data)) return;

    for (let entry of data) {
        if (entry.id === id) {
            return entry;
        } else {
            const node = findNode(entry.children, id);
            if (node) { 
                return node;    
            }           
        }       
    }   
}

第二个函数只获取子 ID,将它们存储在传递的数组中,而不创建任何中间数组:

function getChildIds(node, result = []) {
    if (!node) return;
    if (!Array.isArray(node.children)) return;

    for (let entry of node.children) {
        result.push(entry.id);
        getChildIds(entry, result);
    }
    return result;
}