javascript,递归地在对象的深层嵌套数组中查找值

时间:2018-09-22 05:08:39

标签: javascript

我有一个嵌套的对象数组,具有父子关系:

  [  
   {  
      "id":"5b9ce8d51dbb85944baddfa5",
      "name":"EARBANG",
      "parent_id":0,
      "status":"Inactive",
      "children":[  
         {  
            "id":"5b9ce8d5d978f75e4b1584ba",
            "name":"DIGINETIC",
            "parent_id":"5b9ce8d51dbb85944baddfa5",
            "status":"Active",
            "children":[  
               {  
                  "id":"5b9ce8d5cb79d63c8b38018c",
                  "name":"PREMIANT",
                  "parent_id":"5b9ce8d5d978f75e4b1584ba",
                  "status":"Active",
               }
            ]
         }
      ]
   },
   {  
      "id":"5b9ce8d51650fac75fa359c8",
      "name":"GEEKOLOGY",
      "parent_id":0,
      "status":"Active",
   },
   {  
      "id":"5b9ce8d59f52e801a2e40a97",
      "name":"TOYLETRY",
      "parent_id":0,
      "status":"Inactive",
   },
   {  
      "id":"5b9ce8d5d136fcfed2f3e0dd",
      "name":"PAPRIKUT",
      "parent_id":0,
      "status":"Inactive",
   },
   {  
      "id":"5b9ce8d53afb7a61e188c48e",
      "name":"EYERIS",
      "parent_id":0,
      "status":"Inactive",
   }
]

我在这里想要

1-查找具有ID(例如)的对象5b9ce8d51dbb85944baddfa5

2-递归地迭代该对象的子级数组(如果不为空),并在数组中获取其所有子级,孙级和曾孙级的ID。

所以我的结果将是

{
    "id":"5b9ce8d51dbb85944baddfa5",
    childs: ["5b9ce8d5d978f75e4b1584ba", "5b9ce8d5cb79d63c8b38018c", ...]
}

我尝试了一些在堆栈溢出时可用的解决方案,但无法使其正常工作。

如果有人能帮助我,我的DS不够强大。

谢谢

10 个答案:

答案 0 :(得分:1)

递归搜索ID。

#!/usr/bin/perl

 use strict;
 use warnings;
 use Sample;
print Sample->test_function();

答案 1 :(得分:1)

您可以使用相当标准的递归方法来找到对象。边缘条件是传递给函数的对象是数组。这将进行深度优先搜索。

一旦找到对象,就需要获得后代子代。为了简单起见,我将其设为单独的功能:

0 0

如果找不到ID,它将返回undefined。

答案 2 :(得分:1)

看看我创建的递归搜索id的代码沙箱。找到ID后,它将调用另一个递归来生成child的数组。

console.log(findId(data, "5b9ce8d51dbb85944baddfa5"));
console.log(findId(data, "5b9ce8d5cb79d63c8b38018c"));

以下是上面两个的输出。

enter image description here

https://codesandbox.io/s/m4vowz8qp8

答案 3 :(得分:0)

let input = [
  {
    id: '5b9ce8d51dbb85944baddfa5',
    name: 'EARBANG',
    parent_id: 0,
    status: 'Inactive',
    children: [
      {
        id: '5b9ce8d5d978f75e4b1584ba',
        name: 'DIGINETIC',
        parent_id: '5b9ce8d51dbb85944baddfa5',
        status: 'Active',
        children: [
          {
            id: '5b9ce8d5cb79d63c8b38018c',
            name: 'PREMIANT',
            parent_id: '5b9ce8d5d978f75e4b1584ba',
            status: 'Active'
          }
        ]
      }
    ]
  },
  {
    id: '5b9ce8d51650fac75fa359c8',
    name: 'GEEKOLOGY',
    parent_id: 0,
    status: 'Active'
  },
  {
    id: '5b9ce8d59f52e801a2e40a97',
    name: 'TOYLETRY',
    parent_id: 0,
    status: 'Inactive'
  },
  {
    id: '5b9ce8d5d136fcfed2f3e0dd',
    name: 'PAPRIKUT',
    parent_id: 0,
    status: 'Inactive'
  },
  {
    id: '5b9ce8d53afb7a61e188c48e',
    name: 'EYERIS',
    parent_id: 0,
    status: 'Inactive'
  }
];

function getNestedChildrenId(fileteredObject, children) {
  return fileteredObject.map(item => {
    children.push(item.id);
    if (item.children && item.children.length) {
      getNestedChildrenId(item.children, children);
    }
  });
}

function getParentAndChildrenId(parentId, data) {
  let result = { id: parentId, children: [] };
  let fileteredParent = data.find(({ id }) => id === parentId);
  if (fileteredParent.children) getNestedChildrenId(fileteredParent.children, result.children);
  return result;
}

console.log(getParentAndChildrenId('5b9ce8d51dbb85944baddfa5', input));

console.log(getParentAndChildrenId('5b9ce8d5d136fcfed2f3e0dd', input));

答案 4 :(得分:0)

这是一个搜索递归函数:

function searchRecursive(data, id) {
  let found = data.find(d => d.id === id);
  if (!found) {
    let i = 0;
    while(!found && i < data.length) {
      if (data[i].children && data[i].children.length) {
        found = searchRecursive(data[i].children, id);
      }
      i++;
    }
  }
  return found;
}

答案 5 :(得分:0)

这是一种基本的递归方法,

var data = [{
  "id": "5b9ce8d51dbb85944baddfa5",
  "name": "EARBANG",
  "parent_id": 0,
  "status": "Inactive",
  "children": [{
    "id": "5b9ce8d5d978f75e4b1584ba",
    "name": "DIGINETIC",
    "parent_id": "5b9ce8d51dbb85944baddfa5",
    "status": "Active",
    "children": [{
      "id": "5b9ce8d5cb79d63c8b38018c",
      "name": "PREMIANT",
      "parent_id": "5b9ce8d5d978f75e4b1584ba",
      "status": "Active",
    }]
  }]
}, {
  "id": "5b9ce8d51650fac75fa359c8",
  "name": "GEEKOLOGY",
  "parent_id": 0,
  "status": "Active",
}, {
  "id": "5b9ce8d59f52e801a2e40a97",
  "name": "TOYLETRY",
  "parent_id": 0,
  "status": "Inactive",
}, {
  "id": "5b9ce8d5d136fcfed2f3e0dd",
  "name": "PAPRIKUT",
  "parent_id": 0,
  "status": "Inactive",
}, {
  "id": "5b9ce8d53afb7a61e188c48e",
  "name": "EYERIS",
  "parent_id": 0,
  "status": "Inactive",
}];


function findChildren(obj, output, targetId, found) {
  var _found;
  obj.forEach((child) => {
    if (found || child.id === targetId) {
      if (found) output.push(child.id);
      _found = true;
    }
    if (child.children && child.children.length) {
      findChildren(child.children, output, targetId, _found);
    }
  });
  return output;
}

var res = findChildren(data, [], "5b9ce8d51dbb85944baddfa5");

console.log('res:', res);

答案 6 :(得分:0)

深度优先下降

这是一个通用的实现,一旦谓词函数返回true(希望我们可以在战利品中找到黄金),它就会停止递归:

var loot = {
        box_a: 'seaweed',
        box_b: {
                box_c: [
                        { box_d: 'tuna', box_e: ['gold', 'trash'] }
                ]
        }
};

function descend_obj(item, pred_fn) {
        if (item instanceof Array) {
                return item.some(it => {
                        return descend_obj(it, pred_fn);
                });
        } else if (typeof item === "object") {
                return Object.keys(item).some(k => {
                        return descend_obj(item[k], pred_fn);
                });
        } else {
                return pred_fn(item);
        }
}

let hasGold = descend_obj(loot, function isGold(item) {
        return (item === 'gold')
});

let msg = (hasGold)
        ? 'yaaaay!'
        : 'awwweee';
console.log(msg);//yaaaay!

答案 7 :(得分:0)

您可以使用这种方法:

  var array = [your array];

  function filter(array, id) {
   result = {
    id: id,
    children: []
   };

   array.map(val => {
    if (val.id == id) {
     findChildren(val, result);
    }
   });

   return result;
  }

  function findChildren(obj) {
   if (obj.children && Array.isArray(obj.children)) {
    obj.children.map(val => {
     if (val.id) {
      result.children.push(val.id);
     }
     if (val.children) {
      findChildren(val);
     }
    });
   }
  }

  var search = filter(array, '5b9ce8d51dbb85944baddfa5');

我认为代码很清楚,不需要解释。

答案 8 :(得分:0)

我倾向于不使用递归,因为递归更难于解释该循环,因为:

  1. 要使用递归,您必须事先确切知道函数返回的内容。因为您会在完成之前(在其自身中)调用它。
  2. 使用递归时,您必须牢记同一个函数的多个副本,因为这就是递归的工作方式-函数在结束之前会自行调用。很难不迷失在一堆完全相同的物体中。使用循环更容易,因为一个迭代在另一个迭代开始之前就结束了。

就同步代码而言,递归始终可以用循环代替。

这是非递归解决方案:

function findDescendants(data, key) {
  let ancestor;
  const ancestorStack = [data];      
  while (ancestorStack.length) { // 1- Find an object having id
    const current = ancestorStack.pop();
    for (const item of current) {
      if (item.id === key) {
        ancestor = item;
        break;
      }
      const { children } = current;
      if (children && children.length) {
        ancestorStack.push(children);
      }
    }
  }
  const descendantIds = [];      
  const childrenStack = [ancestor.children];
  while (childrenStack.length) { // 2- get id of all its descendants
    const current = childrenStack.pop();
    for (const item of current) {
      descendantIds.push(item.id);
      const { children } = item;
      if (children && children.length) {
        childrenStack.push(children);
      }
    }
  }
  return {
    id: ancestor.id,
    childs: descendantIds
  }
}

实时演示:https://repl.it/@marzelin/findDescendants

由于此函数执行两项独立的任务,因此最好外包并概括这些任务:

  • function findDeep(predicate, deepProps, data)
  • function gatherDeep(prop, deepProps, data)

然后将findDecendants简化为:

function findDescendants(data, key) {
  const ancestor = findDeep(o => o.id === key, ["children"], data);
  const descendantIds = gatherDeep("id", ["children"], ancestor.children);
  return {
    id: ancestor.id,
    childs: descendantIds
  }
}

答案 9 :(得分:0)

我使自己成为此功能,可能对您也有用。

当您不知道要处理哪种对象时,它会很有帮助...

示例:

var values = [
      {  
        "id":"5b9ce8d51dbb85944baddfa5",
        "name":"EARBANG",
        "parent_id":0,
        "status":"Inactive",
        "children":[  
           {  
              "id":"5b9ce8d5d978f75e4b1584ba",
              "name":"DIGINETIC",
              "parent_id":"5b9ce8d51dbb85944baddfa5",
              "status":"Active",
              "children":[  
                 {  
                    "id":"5b9ce8d5cb79d63c8b38018c",
                    "name":"PREMIANT",
                    "parent_id":"5b9ce8d5d978f75e4b1584ba",
                    "status":"Active",
                 }
              ]
           }
        ]
     },
     {  
        "id":"5b9ce8d51650fac75fa359c8",
        "name":"GEEKOLOGY",
        "parent_id":0,
        "status":"Active",
     },
     {  
        "id":"5b9ce8d59f52e801a2e40a97",
        "name":"TOYLETRY",
        "parent_id":0,
        "status":"Inactive",
     },
     {  
        "id":"5b9ce8d5d136fcfed2f3e0dd",
        "name":"PAPRIKUT",
        "parent_id":0,
        "status":"Inactive",
     },
     {  
        "id":"5b9ce8d53afb7a61e188c48e",
        "name":"EYERIS",
        "parent_id":0,
        "status":"Inactive",
     }
  ]
  //---------------------------------------------------------
  // Strip Down to String Function
  //----------------------------------------------------------
  var depth = 0;
  var stripdown = function(object, find, eol) {
      depth = depth + 1;
      var str = "";
      var s = new function() {
          return {
              // Unique ID generator
              id: new Date().getFullYear() + 
                  new Date().getMonth() + 
                  new Date().getDate() + 
                  new Date().getHours() + 
                  new Date().getMinutes() + 
                  new Date().getSeconds() + 
                  new Date().getMilliseconds(),
              // Spaces for depth
              space: '    ',
              // Index
              index: 0
          }
      };
      while(s.index <= Object.keys(object).length){
          // Every Last Line Has An Undefined Object So Clear Them
          if (Object.keys(object)[s.index] != undefined) {
              // If More Than 1 In The Line Add ',' + eol
              if (s.index > 0) {
                str = str + ',' + eol;
              }
              // Add Spaces For Each Depth Level
              for(var i=0;i < depth;i++) { str = str + s.space; }
              // Add Keys
              str = str + Object.keys(object)[s.index] + ' : ';
              // Add Values
              if (typeof Object.values(object)[s.index] === 'object'){
                  str = str + '{' + eol; // Starting Tag
                  // Add Inner Object Values
                  str = str + stripdown(Object.values(object)[s.index], find, eol);
                  // Add Closing Space
                  for(var i=depth;i > 0;i--) { str = str + s.space; }
                  str = str + '}'; // Closing Tag
                  // Find Object
                  if(str.indexOf(find)>-1){
                    // Lower The Depth 
                    depth = depth - 1;
                    return str + eol;
                  }
              } else {
                  // No Sub Object
                  str = str + Object.values(object)[s.index];
              }
          }
          // Next line
          s.index = s.index + 1;
      }
      // Lower The Depth 
      depth = depth - 1;
      // Return
      return str + eol;
  }
  //---------------------------------------------------------
  console.log(stripdown(values, "PREMIANT", "\n"));

用法:

stripdown( [object Object], SearchFor, "\n" );

将对象树作为字符串返回;

0 : {
    id : 5b9ce8d51dbb85944baddfa5,
    name : EARBANG,
    parent_id : 0,
    status : Inactive,
    children : {
        0 : {
            id : 5b9ce8d5d978f75e4b1584ba,
            name : DIGINETIC,
            parent_id : 5b9ce8d51dbb85944baddfa5,
            status : Active,
            children : {
                0 : {
                    id : 5b9ce8d5cb79d63c8b38018c,
                    name : PREMIANT,
                    parent_id : 5b9ce8d5d978f75e4b1584ba,
                    status : Active
                }
            }
        }
    }
}