从扁平结构制作嵌套对象结构并反向?

时间:2018-06-07 08:25:18

标签: javascript arrays algorithm tree flatten

我有一个平面阵列。像这样:

const inputArray = [
  {
    path: '1',
    id: '1'
  },
  {
    path: '2',
    id: '2'
  },
  {
    path: '3',
    id: '3'
  },
  {
    path: '3.4',
    id: '4'
  },
  {
    path: '3.5',
    id: '5'
  },
  {
    path: '3.4.6',
    id: '6'
  },
  {
    path: '3.4.7',
    id: '7'
  },
  {
    path: '8',
    id: '8'
  },
]

其中path是id的唯一路径。例如,path: '3.5'表示此对象是具有id: '3'的对象的子对象。 path: '3.4.6'path: '3.4'的孩子。 我想把它们收集到嵌套结构中。所以结果应该是这样的。

const result = [
  {
    path: '1',
    id: '1',
    children: []
  },
  {
    path: '2',
    id: '2',
    children: []
  },
  {
    path: '3',
    id: '3',
    children: [
      {
        path: '3.4',
        id: '4',
        children: [
           {
            path: '3.4.6',
            id: '6',
            children: []
          },
          {
            path: '3.4.7',
            id: '7',
            children: []
          },
        ]
      },
      {
        path: '3.5',
        id: '5',
        children: []
      },
    ]
  },
  {
    path: '8',
    id: '8',
    children: []
  },
]

我还需要第二个算法将它们转换回来,从嵌套到扁平结构。你能提出广告建议吗?

更新:数据未排序。 Here是我的尝试,但代码太多而且在某些情况下失败了。我觉得应该有更好的方法来做到这一点。

3 个答案:

答案 0 :(得分:3)

使用Array.reduceArray.findIndexArray.pushArray.shift

转换为树

  • 假设input array按路径排序,否则,您不会对inputArray.sort((a,b) => a.path - b.path);进行排序
  • 减少数组以形成树
  • 通过拆分路径并从中创建数字数组来创建层次结构数组
  • 创建一个将需要3个输入的函数addChildren
    • a - >将插入对象的父对象(数组)
    • c - >需要插入的对象
    • t - >需要插入的对象的层次结构数组
  • 函数获取t的第一个值,如果它是层次结构中的最后一个值 这意味着a是对象的有效占位符。因此, 把它推到那里。如果有剩余的值,那么找到 通过匹配id从数组中占位符。现在,再次打电话给 a的函数将成为匹配对象children数组, c保持不变,t将是剩余的层次结构数组。

const inputArray = [{path:'1',id:'1'},{path:'2',id:'2'},{path:'3',id:'3'},{path:'3.4',id:'4'},{path:'3.5',id:'5'},{path:'3.4.6',id:'6'},{path:'3.4.7',id:'7'},{path:'8',id:'8'}];

const result = inputArray.reduce((a,c) => {
  let t = c.path.split(".").map(Number);
  addChildren(a,c,t);
  return a;
}, []);

function addChildren(a, c, t) {
  let val = t.shift();
  if(!t.length) {
    a.push({...c, children : []});
  } else {
    var i = a.findIndex(({id}) => Number(id) === val);
    addChildren(a[i].children, c, t);
  }
}
console.log(result);

拼合树

  • 创建一个带2个输入的函数
    • a - >输入数组(子数组)
    • r - >结果数组
  • 函数迭代输入数组并推送对象 结果数组并检查任何子节点,如果是,则调用该函数 对于儿童也是如此

var inputArray = [{path:'1',id:'1',children:[]},{path:'2',id:'2',children:[]},{path:'3',id:'3',children:[{path:'3.4',id:'4',children:[{path:'3.4.6',id:'6',children:[]},{path:'3.4.7',id:'7',children:[]},]},{path:'3.5',id:'5',children:[]},]},{path:'8',id:'8',children:[]},];

function flattenArray(a, r) {
  a.forEach(({children, ...rest}) => {
    r.push(rest);
    if(children) flattenArray(children, r)
  });
}
var result = [];
flattenArray(inputArray, result);
console.log(result);

答案 1 :(得分:1)

您可以将对象用作未分类数据的辅助结构并构建树。

为了得到一个平面数组,你可以迭代树并用递归函数连接扁平子数。

function getTree(array) {
    var o = {};
    array.forEach(({ id, path }) => {
        var parents = path.split('.'),
            parent = parents[parents.length - 2];

        Object.assign(o[id] = o[id] || {}, { id, path });
        o[parent] = o[parent] || {};
        o[parent].children = o[parent].children || [];
        o[parent].children.push(o[id]);
    });
    return o.undefined.children;
}

function getFlat(array = []) {
    return array.reduce((r, { id, path, children }) =>
        r.concat({ id, path }, getFlat(children)), []);
}

var input = [{ path: '1', id: '1' }, { path: '2', id: '2' }, { path: '3', id: '3' }, { path: '3.4', id: '4' }, { path: '3.5', id: '5' }, { path: '3.4.6', id: '6' }, { path: '3.4.7', id: '7' }, { path: '8', id: '8' }],
    tree = getTree(input),
    flat = getFlat(tree);

console.log(tree);
console.log(flat);
.as-console-wrapper { max-height: 100% !important; top: 0; }

不保留path的解决方案。

function getTree(array) {
    var o = {};
    array.forEach(({ id, path }) => {
        var parents = path.split('.'),
            parent = parents[parents.length - 2];

        Object.assign(o[id] = o[id] || {}, { id });
        o[parent] = o[parent] || {};
        o[parent].children = o[parent].children || [];
        o[parent].children.push(o[id]);
    });
    return o.undefined.children;
}

function getFlat(array = [], path = []) {
    return array.reduce((r, { id, children }) => {
        var p = path.concat(id);
        return r.concat({ id, path: p.join('.') }, getFlat(children, p));
    }, []);
}

var input = [{ path: '1', id: '1' }, { path: '2', id: '2' }, { path: '3', id: '3' }, { path: '3.4', id: '4' }, { path: '3.5', id: '5' }, { path: '3.4.6', id: '6' }, { path: '3.4.7', id: '7' }, { path: '8', id: '8' }],
    tree = getTree(input),
    flat = getFlat(tree);

console.log(tree);
console.log(flat);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:1)

如果你想要更多的可用性,你可以从输入创建树形结构,然后随意做任何事情(即以你想要的某种格式输出,添加查找某些项目的方法等。)

You can't specify target table 'Person' for update in FROM clause

输出是树的输出,而不是您包含的确切输出 - 取决于您,如何继续进行。