JavaScript:扁平的多维数组到一系列独特的路径



im试图构建树下所有唯一路径的列表/对象的多维数组。

假设此数据...

const data = [
  {
    id: '1',
    items: [
      {
        id: '1.1',
        items: [ { id: '1.1.1' }, { id: '1.1.2' }, { id: '1.1.3' }, ]
      }
    ]
  },
  {
    id: '2',
    items: [
      {
        id: '2.1',
        items: [ { id: '2.1.1' }, { id: '2.1.2' }, { id: '2.1.3' },  ]
      },
      {
        id: '2.2',
        items: [ { id: '2.2.1' } ]
      }
    ]
  }
]

我需要最终得到这样的数组结构。

const result = [
  ['1', '1.1', '1.1.1'],
  ['1', '1.1', '1.1.2'],
  ['1', '1.1', '1.1.3'],
  ['2', '2.1', '2.1.1'],
  ['2', '2.1', '2.1.2'],
  ['2', '2.1', '2.1.3'],
  ['2', '2.2', '2.2.1']
];

每个条目是原始树结构的唯一path的数组。

我将每条路径作为单独的条目遇到真正的麻烦。到目前为止,我已经将路径返回到较低级别,并将底层ID附加到当前路径。

function flatten(items, path = []) {
  let result = [];
  items.forEach( item => {
    path.push(item.id);
    if (item.items && item.items.length) {  
      result.push(flatten(item.items, path.slice(0) )); //slice to clone the array
    }
    else {
      result.push(...path);
    }
  });
  return result;
}

这是JS小提琴...

https://jsfiddle.net/9ptdm1ve/

您可以使用 reduce()方法创建递归函数并因此返回数组。您可以使用concat()方法创建prev数组的副本,以便在每个递归级别上都有新副本,因为数组是通过参考传递的,否则您将更改原始数组。

const data = [{"id":"1","items":[{"id":"1.1","items":[{"id":"1.1.1"},{"id":"1.1.2"},{"id":"1.1.3"}]}]},{"id":"2","items":[{"id":"2.1","items":[{"id":"2.1.1"},{"id":"2.1.2"},{"id":"2.1.3"}]},{"id":"2.2","items":[{"id":"2.2.1"}]}]}]
function build(data, prev = []) {
  return data.reduce(function(r, e) {
    const copy = prev.concat(e.id)
    if (e.items) r = r.concat(build(e.items, copy))
    else r.push(copy)
    return r;
  }, [])
}
const result = build(data);
console.log(result)

共享foreach回调中的更新路径。它应该是本地的。

function flatten(items, path = []) {
  let result = [];
  items.forEach(item => {
    let localPath = path.slice(0);
    localPath.push(item.id);
    if (item.items && item.items.length) {  
      result.push(flatten(item.items, localPath));
    } else {
      result.push(localPath);
    }
  });
  return result;
}

您可以使用内部方法,该方法将所有完整的路径推向相同的结果数组:

const data = [{"id":"1","items":[{"id":"1.1","items":[{"id":"1.1.1"},{"id":"1.1.2"},{"id":"1.1.3"}]}]},{"id":"2","items":[{"id":"2.1","items":[{"id":"2.1.1"},{"id":"2.1.2"},{"id":"2.1.3"}]},{"id":"2.2","items":[{"id":"2.2.1"}]}]}]
function flatten(items) {
  const result = [];
  const iterateItems = (items, path = []) =>
    items.forEach(({ id, items }) => {
      const localPath = [...path, id];
      if (items)
        iterateItems(items, localPath);
      else
        result.push(localPath);
    });
  iterateItems(items);
  return result;
}
console.log(flatten(data));

另一个选择是使用Array.map(),并通过扩散到Array.concat()

来弄平每个阶段的结果

const data = [{"id":"1","items":[{"id":"1.1","items":[{"id":"1.1.1"},{"id":"1.1.2"},{"id":"1.1.3"}]}]},{"id":"2","items":[{"id":"2.1","items":[{"id":"2.1.1"},{"id":"2.1.2"},{"id":"2.1.3"}]},{"id":"2.2","items":[{"id":"2.2.1"}]}]}];
const flatten = (arr, path = []) => 
  [].concat(...arr.map(({ id, items }) => items ? 
    flatten(items, [...path, id]) : [[...path, id]]
  ));
  
const result = flatten(data);
console.log(result);

最新更新