递归方式的层次树构造逻辑

Construction logic for Hierarchial tree in Recursion fashion

var cellData = [];
function constructCells(graph, cell) {
  var cellDataObj = {};
  var outgoingEdges = graph.getOutgoingEdges(cell);
  cellDataObj.id = cell.id;
  cellDataObj.value = cell.value;

  if (outgoingEdges.length) {
    cellDataObj.children = [];
    _.each(outgoingEdges, vertex => {
      const target = vertex.target;
      var targetEdges = graph.getOutgoingEdges(target);
      if (targetEdges.length) {
        cellDataObj.children.push({
          id: target.id,
          value: target.value,
          children: getChildrens(graph, target)
        });
      } else {
        cellDataObj.children.push({ id: target.id, value: target.value });
      }
    });
  }
  cellData.push(cellDataObj);
}

function getChildrens(graph, cell) {
  var cells = [];
  var outgoingEdges = graph.getOutgoingEdges(cell);
  _.each(outgoingEdges, vertex => {
    cells.push({
      id: vertex.target.id,
      value: vertex.target.value
    });
  });
  return cells;
}

上面的代码在第一级和第二级之前工作得很好,即直到 v3 节点,它构造 v4 和 v5 作为它的 childrens。但是我在这里的某个地方失去了逻辑,如果成立 children.

则无法为以下节点构建

结果是:

Looking forward for logic correction required for multilevel nesting i.e for the level of V6 and V7 level nodes.

您可以考虑以下图片作为预期参考:

Flat 到 json 转换,抱歉,我无法 post 代码,因为包含库数据和代码需要清理。

要从平面列表到树,您不需要递归。反之亦然。


以下是使用单个循环从平面列表到嵌套结构的方法:

  • 创建一个空对象,用于按 ID 存储节点
  • 创建一个空对象来存储在我们处理它们的父节点
  • 之前出现的节点
  • 遍历所有条目
    • 创建节点
    • 检查我们之前是否看到节点将此 ID 引用为它们的父节点
      • 如果我们这样做了,用这些节点预填充子数组
    • 将节点添加到使用其 id 作为键的对象
    • 检查对象是否已经包含节点的父节点
      • 如果是,则将新节点推送到其父子数组
      • 如果没有,将该节点索引为临时孤儿
    • 检查节点是否为根节点,如果是则存储
  • return根节点

在代码中:

const flat = [
  { id: 1, parentId: 3 },
  { id: 3, parentId: 8 },
  { id: 4, parentId: 6 },
  { id: 6, parentId: 3 },
  { id: 7, parentId: 6 },
  { id: 8, parentId: null },
  { id: 10, parentId: 8 },
  { id: 13, parentId: 14 },
  { id: 14, parentId: 10 }
];

const toTree = nodes => {
  const index = {};
  const orphans = {};
  let root = null;
  
  nodes.forEach(
    ({ id, parentId }) => {
      const node = { id, children: orphans[id] || [] };
      index[id] = node;

      const parent = index[parentId];
      
      if (!parent) {
        if (orphans[parentId]) orphans[parentId].push(node)
        else orphans[parentId] = [node];
      } else {
        parent.children.push(node);
      }

      if (parentId === null) root = node;
    }
  );
  
  return root;
}
  

console.log(JSON.stringify(toTree(flat), null, 2));


返回平面列表:

  • 从根节点开始调用flatten
  • 将根节点连接到结果数组
  • 如果它有子节点,则使用根节点 ID 作为父节点 ID(即递归)展平每个子节点

const tree = {"id":8,"children":[{"id":3,"children":[{"id":1,"children":[]},{"id":6,"children":[{"id":4,"children":[]},{"id":7,"children":[]}]}]},{"id":10,"children":[{"id":14,"children":[{"id":13,"children":[]}]}]}]};

const flatten = (node, parentId = null) => 
  [{ id: node.id, parentId }].concat(
    node.children.flatMap(
      child => flatten(child, node.id)
    )
  );
    
console.log(flatten(tree));