JavaScript 获取嵌套数组对象树中下一个子对象值的总和

JavaScript get sum of next child object value in nested Array Object Tree

我有一个类似于下面的对象。它具有树结构。每个父对象都会有它的子对象。我想要做的是,遍历每个子对象并获取对象的总和并将其放入父对象中。

顶级对象将拥有其所有子对象的总和,二级父对象将拥有其子对象的总和,依此类推。

[
    {
        accountNo: "1",
        children: [
            {
                accountNo: "1.1",
                balance: {credit: 100, debit: 50},
                children: [
                    {
                        accountNo: "1.1.1",
                        balance: {credit: 50, debit: 100},
                        children: [
                            {
                                accountNo: "1.1.1.1",
                                balance: {credit: 50, debit: 100}
                            }
                        ]
                    }
                ]
            },
            {
                accountNo: "1.2",
                balance: {credit: 100, debit: 50}
            }
        ]
    },
    {
        accountNo: "2",
        children: [
            {
                accountNo: "2.1",
                balance: {credit: 100, debit: 50}
            },
            {
                accountNo: "2.2",
                balance: {credit: 100, debit: 50},
                children: [
                    {
                        accountNo: "2.2.1",
                        balance: {credit: 50, debit: 100},
                        children: [
                            {
                                accountNo: "2.2.1.1",
                                balance: {credit: 50, debit: 100}
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

想要的答案如下。

    [
    {
        accountNo: "1",
        final: {credit: 300, debit: 300},
        children: [
            {
                accountNo: "1.1",
                balance: {credit: 100, debit: 50},
                final: {credit: 200, debit: 250},
                children: [
                    {
                        accountNo: "1.1.1",
                        balance: {credit: 50, debit: 100},
                        final: {credit: 100, debit: 200},
                        children: [
                            {
                                accountNo: "1.1.1.1",
                                balance: {credit: 50, debit: 100},
                                final: {credit: 50, debit: 100}
                            }
                        ]
                    }
                ]
            },
            {
                accountNo: "1.2",
                balance: {credit: 100, debit: 50},
                final: {credit: 100, debit: 50}
            }
        ]
    },
    {
        accountNo: "2",
        final: {credit: 150, debit: 150},
        children: [
            {
                accountNo: "2.1",
                balance: {credit: 100, debit: 50}
            },
            {
                accountNo: "2.2",
                balance: null,
                final: {credit: 50, debit: 100},
                children: [
                    {
                        accountNo: "2.2.1",
                        balance: null,
                        final: {credit: 50, debit: 100},
                        children: [
                            {
                                accountNo: "2.2.1.1",
                                balance: {credit: 50, debit: 100},
                                final: {credit: 50, debit: 100}
                            }
                        ]
                    }
                ]
            }
        ]
    }
]

有什么方法可以实现这个目标吗? 注意:需要从 balance 对象中获取总量,Balance 对象有时会为 null,在这种情况下,不需要从该对象中添加任何内容。 例子.

我尝试使用递归 map 但没有成功。 我试过类似下面的东西。代码在 NodeJS.

parentArray.map(async ele => {
    ele.final = { credit: 0, debit: 0 };
    getChildBalance(ele);
})

async function getChildBalance(object){
    let final = { credit: 0, debit: 0 };
    object.children.map(async child => {
        let fin = await getChildBalance(child);
        final = {
            credit: final.credit + child.balance.credit + fin.final.credit,
            debit: final.debit + child.balance.debit + fin.final.debit
        };
    })
    object.final;
}

如果您想将最终余额添加到现有对象,此方法有效:

function addFinalBalance(object) {
    const final = { credit: 0, debit: 0 };
    
    if (object.balance) {
        final.credit += object.balance.credit;
        final.debit += object.balance.debit;
    }
  
    if (object.children) {
      object.children.forEach(child => {
          addFinalBalance(child);
          final.credit += child.final.credit;
          final.debit += child.final.debit;
      });
    }
    object.final = final;
}

// usage:
parentArray.forEach(addFinalBalance);

您也可以使用这种函数式解决方案,它使用最终余额创建一个新对象,并保持现有对象不变。

function addChildBalanceImmutable(object) {
    const children = object.children ? object.children.map(addChildBalanceImmutable) : [];
  
    const final = {
        credit: (object.balance ? object.balance.credit : 0) + children.reduce((s, x) => s + x.final.credit, 0),
        debit: (object.balance ? object.balance.debit : 0) + children.reduce((s, x) => s + x.final.debit, 0)
    };
  
    return { ...object, final, children };
}

// usage
const parentArrayWithFinalBalance = parentArray.map(addFinalBalanceImmutable);

这是一个相当简单的函数式方法。我们映射输入。对于每个项目,我们递归地处理子项,然后将它们的 final 属性与当前项(如果它们都存在)组合到 final 节点中。我们包含一个简单的 sum 辅助函数,而不是重复 reduce 调用。

我们不假设显示的是所有字段,因此我们使用 ...rest 参数来捕获剩余的字段。 ___ 参数是因为我们在 map 调用中,它添加了 indexarray 参数,我们希望在默认之前忽略它们我们的 kids 论点。如果这太难看,我们可以使用 call 函数或在函数体中使用局部 kids 变量。

const sum = (ns) => ns .reduce ((a, b) => a + b, 0)

const collect = (xs) => 
  xs .map (({balance, children = [], ...rest}, _, __, kids = collect (children)) => ({
    ...rest,
    balance,
    final: {
      credit: (balance?.credit ?? 0) + sum (kids .map (({final: {credit}}) => credit)),
      debit: (balance?.debit ?? 0) + sum (kids .map (({final: {debit}}) => debit))
    },
    ...(kids.length ? {children: kids} : {})
  }))

const input = [{accountNo: "1", children: [{accountNo: "1.1", balance: {credit: 100, debit: 50}, children: [{accountNo: "1.1.1", balance: {credit: 50, debit: 100}, children: [{accountNo: "1.1.1.1", balance: {credit: 50, debit: 100}}]}]}, {accountNo: "1.2", balance: {credit: 100, debit: 50}}]}, {accountNo: "2", children: [{accountNo: "2.1", balance: {credit: 100, debit: 50}}, {accountNo: "2.2", balance: {credit: 100, debit: 50}, children: [{accountNo: "2.2.1", balance: {credit: 50, debit: 100}, children: [{accountNo: "2.2.1.1", balance: {credit: 50, debit: 100}}]}]}]}]

console .log (
JSON .stringify (
  collect(input)
, null, 4)
)
.as-console-wrapper {max-height: 100% !important; top: 0}