什么是找到该对象的直接或间接子对象数量的有效方法

时间:2018-01-16 03:07:18

标签: javascript arrays performance object javascript-objects

JavaScript对象数组,例如: 让objectArray =

[
{ id: 0, parentId: null}, 
{ id: 4, parentId: 3},
{ id: 1, parentId: 0}, 
{ id: 3, parentId: 2},
{ id: 2, parentId: 0}
]

其中parentId在不为null时引用数组中另一个id = parentId的对象。这些对象形成了一种可以像树一样可视化的关系:

enter image description here

我们必须在JS中创建一个函数,给定一个id返回该对象的直接或间接子对象的数量的计数。例如,如果函数的值为3,则应返回1,如果函数的值为0,则返回4。

我尝试了什么,

var count = 0;
var selected = [];

let objectArray = [
      { id: 0, parentId: null},
      { id: 4, parentId: 3},
      { id: 1, parentId: 0},
      { id: 3, parentId: 2},
      { id: 2, parentId: 0}
];


var factorial = function(objectArray, selected, num) {
  // console.log('5 - Array = ', Array );
  console.log('6 - selected = ', selected );
  // do stuff here

  for (var i = 0; i < objectArray.length; i++) {
    console.log('19 -  num = ', num );
    console.log('20 -  i =', i, objectArray[i] );
    console.log('21-  parent_id =', i, objectArray[i].parentId  );

    if ( objectArray[i].parentId  === num ) {
        console.log('   yes with num =', num );
        count = count + 1;
        selected.push(objectArray[i]);

        // selected.pop(selected[i]);

        console.log(' 18-  count = ', count );
    }
    console.log('20 ============ done =========== i= ', i );

    console.log(' ============ selected ==== ', selected );
    console.log('25 ============ count =========== ', count );
  }


  // if (selected.length >= 0 ) { // terminal case
  if ( selected.length == 0 ) { // terminal case
  // if ( count >= 6 ) {
    console.log('29-  %%%%%%%%%%%% if selected.length =', selected.length);
    console.log('29-  %%%%%%%%%%%% if  count %%%%%%%%% ', count );
    return count;
  } else { // block to execute
    console.log(' ****** in else --  now calling Selected Arr ******');


    for (var i = 0; i < selected.length; i++) {
        console.log(  '52-  selected[i].id  =',  selected[i]  );
      factorial (objectArray, selected, selected[i].id  );
    }

    // return ( factorial (objectArray, selected, num ));
  }

};



factorial(objectArray, selected, 0);

3 个答案:

答案 0 :(得分:0)

使用递归,这回答了提供的示例:

let objectArray = [
      { id: 0, parentId: null},
      { id: 4, parentId: 3},
      { id: 1, parentId: 0},
      { id: 3, parentId: 2},
      { id: 2, parentId: 0}
];

let count = 0;

function findChildId(topId) {
    if(topId === 0) {
    count = objectArray.length - 1;
    return
  } 

  for(i = 1; i < objectArray.length; i++) {
    if(objectArray[i].parentId === topId) {
        let childId = objectArray[i].id
      if(childId) {
        count++;
        findChildId(childId);
      }
    }
  }
}

findChildId(4); // use which ever id you are interest in
console.log(count);  // 0 for node 4

答案 1 :(得分:0)

您可以尝试这种方法,从给定对象创建地图并添加父和子。从结果对象中找到childCount,如下所示:

var rels = [
{ id: 0, parentId: null}, 
{ id: 4, parentId: 3},
{ id: 1, parentId: 0}, 
{ id: 3, parentId: 2},
{ id: 2, parentId: 0}
];

 // create a map of nodes
 var nodeMap = distinct(rels);
 nodeMap = graph(rels,  nodeMap); // update parent and children

 childCount(3, nodeMap);
 childCount(0, nodeMap);

function distinct(nodes){
     return nodes.reduce(function(prev, curr){
          prev[curr.id] = {id:curr.id, parent:null, children:[]}
      return prev;
    }, {});
}

function graph(nodes, nodeMap){
    nodes.forEach(function(node){       
       if (node.parentId !== null) {        
           var parentNode = nodeMap[node.parentId]
           var childNode = nodeMap[node.id];

           console.log(parentNode, childNode)

           childNode.parent =  parentNode;
           parentNode.children.push(childNode);
       }
      });

   return nodeMap;
 }

 function childCount(id, nodeMap){
    var node = nodeMap[id];

    console.log('cc', id, node);

    return  node.children.reduce(function(prev, curr){ 
                         return prev + childCount(curr.id, nodeMap) 
                 }, 
                 node.children.length);
 }

答案 2 :(得分:0)

写效率最高的是一个简单的递归函数,如

 function countChild( objectArray, id) {
     let count = 0;
     objectArray.forEach( obj => {
         if( obj.parentId === id) {
            count = count + 1 + childCount(objectArray, obj.id);
         }
     });
     return count;
 }

但是,对于每个后代对象,它会遍历对象数组一次。

为每一代收集成员对象的方法,每代只能通过输入数组一次,这可能至少在数学上更有效:

let objectArray = [
{ id: 0, parentId: null}, 
{ id: 4, parentId: 3},
{ id: 1, parentId: 0}, 
{ id: 3, parentId: 2},
{ id: 2, parentId: 0}
];

function childCount(objectArray, id, children) {
     let count = 0;

     // count children of id value:

     if( !children) {
         children = new Set();
         objectArray.forEach( obj => {
             if( obj.parentId === id) {
                ++count;
                children.add(obj.id);
             }
         });
         if( count) {
             count += childCount( objectArray, null, children);
         }
         return count;
     }

     // or count children of children

     let nextGen = new Set();
     objectArray.forEach( obj => {
         if( children.has( obj.parentId)) {
             ++count;
             nextGen.add( obj.id);
         }
     });
     if( count) {
         count += childCount( objectArray, null, nextGen)
     }
     return count;
}

console.log(  childCount(objectArray, 0)  );

通过输入数组减少迭代次数的好处是否值得额外的复杂性和特定应用程序的开销很难说 - 我没有进一步研究过。