用JavaScript按parentId对扁平数组进行排序

3
每个父元素都应包含所有子类别的总数。如果解决方案仅使用Array对象方法且不使用while循环,那将非常好。
这是基本结构的示例:
const base = [
  { id: 1, count: 2, parentId: null },
  { id: 2, count: 4, parentId: 1 },
  { id: 3, count: 0, parentId: 2 },
  { id: 6, count: 8, parentId: 3 },
  { id: 7, count: 8, parentId: 3 },
  { id: 8, count: 2, parentId: 7 },
  { id: 4, count: 2, parentId: null },
  { id: 5, count: 1, parentId: 4 },
];

这是它应该看起来的样子:
const expected = [
  { id: 1, count: 2, total: 24, parentId: null },
  { id: 2, count: 4, total: 22, parentId: 1 },
  { id: 3, count: 0, total: 18, parentId: 2 },
  { id: 6, count: 8, total: 8, parentId: 3 },
  { id: 7, count: 8, total: 10, parentId: 3 },
  { id: 8, count: 2, total: 2, parentId: 7 },
  { id: 4, count: 2, total: 3, parentId: null },
  { id: 5, count: 1, total: 1, parentId: 4 },
];

这是我的当前代码。我认为在这里我需要到达最后一层,然后从底部开始将前一个层与当前层的count属性值连接起来,这就是为什么我使用了命名IIFE。
let c = a.map(cat => {
  const top = a.filter(v => cat.id === v.parentId);
  let test;
  return ({
    ...cat,
    total: (test = categs => {
      return categs.reduce((acc, val) => {
         /* ??? */
         return acc + val.count
      }, cat.count);
    })(top)
  })
})

4
Stack Overflow 要求你展示你自己尝试实现目标的过程。这里不是要求教程,也不是找免费程序员的地方。请阅读 可以询问哪些话题如何提出好问题完美问题 - icecub
2个回答

2
这是一个尝试:

最初的回答:

const base = [
  { id: 1, count: 2, parentId: null },
  { id: 2, count: 4, parentId: 1 },
  { id: 3, count: 0, parentId: 2 },
  { id: 6, count: 8, parentId: 3 },
  { id: 7, count: 8, parentId: 3 },
  { id: 8, count: 2, parentId: 7 },
  { id: 4, count: 2, parentId: null },
  { id: 5, count: 1, parentId: 4 },
];

const getDescendants = ({ id }) =>
  base.reduce((acc, n) => n.parentId === id ? [...acc, n, ...getDescendants(n)] : acc, []);
const expected =
  base.map(record => ({
    ...record,
    total: getDescendants(record).reduce((acc, cur) => acc + cur.count, record.count)
  }));

console.log(expected);

这里的关键是getDescendants函数。它获取一个数组,该数组包含所有元素,其parentId属性等于当前记录的id与递归应用该函数确定的该节点的所有后代的连接。
解决方案并不高效,但考虑到问题明确禁止使用某些核心编程结构,我怀疑这不是一个要求。
以下是另一种方法,递归修改原始数组:

const base = [
  { id: 1, count: 2, parentId: null },
  { id: 2, count: 4, parentId: 1 },
  { id: 3, count: 0, parentId: 2 },
  { id: 6, count: 8, parentId: 3 },
  { id: 7, count: 8, parentId: 3 },
  { id: 8, count: 2, parentId: 7 },
  { id: 4, count: 2, parentId: null },
  { id: 5, count: 1, parentId: 4 },
];

const addToTotal = (id, count) => id !== null && base.forEach(n => {
  if (n.id === id) {
    n.total = (n.total || 0) + count;
    addToTotal(n.parentId, count);
  }
});
base.forEach(n => {
  n.total = (n.total || 0) + n.count;
  addToTotal(n.parentId, n.count);
});

console.log(base);


1
如果您的集合已经排序并且只需要计算总数。我使用reduceRight来节省循环次数并避免突变。

const base = [
  { id: 1, count: 2, parentId: null },
  { id: 2, count: 4, parentId: 1 },
  { id: 3, count: 0, parentId: 2 },
  { id: 6, count: 8, parentId: 3 },
  { id: 7, count: 8, parentId: 3 },
  { id: 8, count: 2, parentId: 7 },
  { id: 4, count: 2, parentId: null },
  { id: 5, count: 1, parentId: 4 },
];

const rs = base.reduceRight((acc, o) => {
  const total = acc.filter(n => n.parentId === o.id).reduce((x, y) => x + y.total, 0)
  return acc.concat({...o, total: total + o.count})
}, [])

console.log(rs.reverse());


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接