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
调用中,它添加了 index
和 array
参数,我们希望在默认之前忽略它们我们的 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}
我有一个类似于下面的对象。它具有树结构。每个父对象都会有它的子对象。我想要做的是,遍历每个子对象并获取对象的总和并将其放入父对象中。
顶级对象将拥有其所有子对象的总和,二级父对象将拥有其子对象的总和,依此类推。
[
{
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
调用中,它添加了 index
和 array
参数,我们希望在默认之前忽略它们我们的 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}