将平面定义的树转换为深度树,JavaScript

时间:2019-04-03 08:16:43

标签: javascript lodash

对于输入的扁平树:

let input = [{
        levelId: '1'
    }, {
        levelId: '1.1'
    }, {
        levelId: '1.1.1'
    }, {
        levelId: '1.2'
    }, {
        levelId: '2'
    }, {
        levelId: '2.1.1'
    }
]

将其转换为多级树的最佳方法是什么,其中levelId定义树的级别:

let output = [{
        levelId: '1',
        children: [{
                levelId: '1.1',
                children: [{
                        levelId: '1.1.1'
                    }
                ]
            }
        ]
    }, {
        levelId: '2',
        children: [{
                levelId: '2.1.1'
            }
        ]
    }
]

使用Lodash。

2 个答案:

答案 0 :(得分:2)

我首先根据对象级别对数组进行排序,然后创建一个中间对象以将每个级别ID映射到对象本身,并从中间对象中找到其父对象。然后我输出一个没有父对象的数组。

希望获得帮助。

var input = [
  {
	levelId: '1'
  },
  {
	levelId: '1.1'
  },
 {
	levelId: '1.1.1'
  },
  {
	levelId: '1.2'
  },
  {
	levelId: '2'
  }, 
  {
	levelId: '2.1.1'
  },
  {
	levelId: '3.1'
  },
  {
	levelId: '3.1.1'
  }
];


function exec(input){

	var temp = {};
	
	//Sort the array by level then create an intermediate object that map level id with the level object and map with its parent
	input.sort((a,b) => a.levelId.split(".").length - b.levelId.split(".").length).forEach( lvl => {
		temp[lvl.levelId] = lvl;
		
		if(lvl.levelId.indexOf('.') !== -1){
			var parentLevelId = lvl.levelId;
			var parent = undefined;
			//Search parent level by level (ie. 3.1.1 -> 3.1 -> 3)
			do{
				if(parentLevelId.indexOf('.') === -1) break;
				parentLevelId = parentLevelId.substr(0, parentLevelId.lastIndexOf("."));
				parent = temp[parentLevelId];
			}while(typeof parent === 'undefined')
			
			if(typeof parent !== 'undefined'){
				if(typeof parent.children === 'undefined'){
					parent.children = [];
				}
				parent.children.push(lvl);
				lvl.parent = parent;
			}
		}
	});
	
	
	//push the root object (level object that has no parent) to an output array
	var output = [];
	for(var key in temp){
		if(typeof temp[key].parent !== 'undefined'){
			delete temp[key]["parent"];
		}else{
			output.push(temp[key]);
		}
	}

	return output;

}


console.log(JSON.stringify(exec(input), 0, 3));

答案 1 :(得分:0)

另一种方法:

  • 在第一遍中,在输入中找到节点时从节点构建一棵树。
  • 然后在第二遍中,重新组织其父节点存在于树中的所有节点。

代码:

let input = [{
        levelId: '1'
    }, {
        levelId: '2.1.1'
    }, {
        levelId: '2.1.1.2.5'
    }, {
        levelId: '1.1'
    }, {
        levelId: '1.2'
    }, {
        levelId: '2'
    }, {
        levelId: '1.1.1.1.1'
    }, {
        levelId: '3.1.1.1.1'
    }
]

console.log(JSON.stringify(treeify(input)))

function treeify(input) {

  let built = {},
      result = { levelId:"", children:[] };

// First pass: build the tree in the order you encounter the nodes:  
  buildTree();
// Second pass: look for children already having an ancestor   
  reorganize(result);  
// For return value, start with list of top level nodes    
  return result.children

// --- First pass: build tree from flat list
  function buildTree() {
    for (let o of input) {
      let parentId = getParentId(o.levelId);
      addChild(built[parentId]||result,o);
      built[o.levelId] = o;
    }
  }

// --- Second pass: switch parents if found
  function reorganize(node) {
    if (!("children" in node)) return;
// Backward loop, as items will be removed during the loop    
    for (let i=node.children.length-1;i>=0;i--) {      
      let c = node.children[i];
// Attach node to first ancestor found      
      for(let parentId = getParentId(c.levelId);parentId;parentId=getParentId(parentId)) {
        if (parentId in built) {
          if (built[parentId]==node) {
            break;  // Already in right position
          }
          addChild(built[parentId],c);
          node.children.splice(i,1);
          break;
        }
      }
    }
// Do it recursively on all child nodes    
    node.children.forEach(reorganize);    
  }

// --- Insert a child    
  function addChild(parent,child) {
    if (!("children" in parent)) {
      parent.children = [];
    } 
    parent.children.push(child);
  }

// --- Determine parent id (by splitting off the last segment of the ID)
  function getParentId(id) {
    return id.replace(/^\d+$|\.\d+$/,"")
  }

}