json樹狀結構的生成

數據庫存儲結構爲平鋪的結構:javascript

[
{id:1 , parentId: 0, name: '', level: 0},
{id:2 , parentId: 0, name: '', level: 0},
{id:3 , parentId: 2, name: '', level: 1},
{id:4 , parentId: 2, name: '', level: 1},
{id:5 , parentId: 4, name: '', level: 2},
]

須要轉換成樹狀結構:java

{
	children:[
		{
			id: 1,
			name: ''
		},
		{
			id: 2,
			name: '',
			children: [
				{
					id: 3
				},
				{
					id: 4,
					children: [
						{
							id: 5
						}
					]
				}
			]
		},
	]
}

 

算法以下:node

const setPath = (parent, arr) => {
  const children = arr.filter(item => item.parentId === parent.id);
  children.forEach((child, i) => {
    child.path = [ ...parent.path, i ];
    setPath(child, arr);
  });
  const myfn = path => {
    return path.map(p => `children[${p}]`).join('.');
  };
  const obj = {};

  return fn => {
    if (!fn) fn = myfn;
    arr = arr.filter(item => item.path !== undefined);
    arr.sort((a, b) => {
      return a.path.length - b.path.length;
    });
    arr.forEach(item => {
      _.set(obj, fn(item.path), item);
    });

    return obj;
  };
};


const res = yield dao.query({ solutionId }); // 從數據庫拿到數據平鋪的結構
generateMethod=undefined 通常狀況下不用傳生成方法
//若是有須要,好比只要二級結構,不須要到3級別,那麼改變generateMethod便可
/*
generateMethod = path => {
      if (path.length === 2) return 'nouse';
      return path.map(p => `children[${p}]`).join('.');
}
*/
const tree = setPath({ id: 0, path: [] }, res)(generateMethod);

樹既然生成了,如何經過給定的葉子節點拿到剪修過的樹。樹的分支只包含到給定的葉子,其他的分支修剪掉。算法

const shake = (tree, fn) => {
  const arr = [];
  const path = [];
  const a = {};
  function find(node, path) {
    if (node.children) {
      node.children.forEach((child, i) => find(child, [ ...path, i ]));
    } else {
      if (fn(node)) {
        arr.push(path);
      }
    }
  }
  function deleteNullNode(tree) {
    if (tree.children) {
      tree.children = tree.children.filter(c => c);
      tree.children.forEach(c => deleteNullNode(c));
    }
  }
  find(tree, path);
  arr.forEach(p => {
    for (let i = 1; i <= p.length; i++) {
      const _p = p.slice(0, i).map(c => `children[${c}]`).join('.');
      if (_.has(a, _p)) {
        continue;
      }
      _.set(a, _p, _.omit(_.get(tree, _p), 'children'));
    }
  });
  deleteNullNode(a);
  return a;
};

使用:數據庫

shake(tree, leaf => leaf.id == 5 )

 

算法還有不少改進的地方,有些內置的處理須要抽象。後續再更新。code

相關文章
相關標籤/搜索