我有一个深度嵌套的 javascript 对象,其子对象的数量不受限制。每个孩子都有一个值和一个总值。 TotalValue 应该是其所有子级和子级的所有值的总和。我怎样才能做到这一点?
目前我只能使用递归函数循环整个对象:
// Recursive function
_.each(names, function(parent) {
if(parent.children.length > 0) {
recursiveFunction(parent.children);
}
});
function recursiveFunction(children){
_.each(children, function(child) {
if(child.children.length > 0) {
recursiveFunction(child.children)
}
});
};
// Deeply nested javascript object
var names = {
name: 'name-1',
value: 10,
valueTotal: 0, // should be 60 (name-1.1 + name-1.2 + name-1.2.1 + name-1.2.2 + name-1.2.2.1 + name-1.2.2.2)
children: [{
name: 'name-1.1',
value: 10,
valueTotal: 0,
children: []
}, {
name: 'name-1.2',
value: 10,
valueTotal: 0, // should be 40 (name-1.2.1 + name-1.2.2 + name-1.2.2.1 + name-1.2.2.2)
children: [{
name: 'name-1.2.1',
value: 10,
valueTotal: 0,
children: []
}, {
name: 'name-1.2.2',
value: 10,
valueTotal: 0, // should be 20 (name-1.2.2.1 + name-1.2.2.2)
children: [{
name: 'name-1.2.2.1',
value: 10,
valueTotal: 0,
children: []
}, {
name: 'name-1.2.2.2',
value: 10,
valueTotal: 0,
children: []
}]
}]
}]
}
}
所以事实上你想做这样的事情: 每个 elem 都会向他的孩子询问其值,这些孩子会做同样的事情并返回他们的总值加上他们自己的值。
function sumUp(object){
object.totalValue = 0;
for(child of object.children){
object.totalValue += sumUp(child);
}
return object.totalValue + object.value;
}
像这样开始:
const totalofall = sumUp(names);
console.log(names); //your expected result.
您可以使用带有迭代和递归方法的纯 JavaScript,并对本地总数进行一些健全性检查。
function calculateValues(o) {
o.valueTotal = (o.children || []).reduce(function (r, a) {
calculateValues(a);
return r + (a.value || 0) + (a.valueTotal || 0);
}, 0);
}
var names = { name: 'name-1', value: 10, valueTotal: 0, children: [{ name: 'name-1.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2', value: 10, valueTotal: 0, children: [{ name: 'name-1.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2', value: 10, valueTotal: 0, children: [{ name: 'name-1.2.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2.2', value: 10, valueTotal: 0, children: [] }] }] }] };
calculateValues(names);
console.log(names);
.as-console-wrapper { max-height: 100% !important; top: 0; }
不太喜欢重新发明轮子,并建议使用库来提高可读性和可维护性。我们现在使用 object-scan 进行大部分数据处理。一旦您了解如何使用它,它的用途就非常广泛。无论如何,这是您问题的可能解决方案
// const objectScan = require('object-scan');
const injectSums = (data) => {
objectScan(['**.children'], {
filterFn: ({ parent, value: children }) => {
parent.valueTotal = children
.map(({ valueTotal, value }) => valueTotal + value)
.reduce((a, b) => a + b, 0);
}
})(data);
};
const names = { name: 'name-1', value: 10, valueTotal: 0, children: [ { name: 'name-1.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2', value: 10, valueTotal: 0, children: [ { name: 'name-1.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2', value: 10, valueTotal: 0, children: [ { name: 'name-1.2.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2.2', value: 10, valueTotal: 0, children: [] } ] } ] }] };
injectSums(names);
console.log(names);
// => { name: 'name-1', value: 10, valueTotal: 60, children: [ { name: 'name-1.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2', value: 10, valueTotal: 40, children: [ { name: 'name-1.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2', value: 10, valueTotal: 20, children: [ { name: 'name-1.2.2.1', value: 10, valueTotal: 0, children: [] }, { name: 'name-1.2.2.2', value: 10, valueTotal: 0, children: [] } ] } ] } ] }
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
免责声明:我是object-scan
的作者这对我有用。它将对象中先前的计数值添加到总计数中。这个可以稍后减去
function sumUpTree(
obj,
{ key = "count", totalKey = "totalCount", childrenKey = "children" }
) {
obj[totalKey] =
obj[key] +
(obj[childrenKey] || []).reduce(function (r, child) {
sumUpTree(child);
return r + (child[totalKey] || 0);
}, 0);
}
这受到以上 Jonas Wilms 和 Nina Scholz
的回答的启发