JavaScript - 如何在递归期间重置局部变量?
JavaScript - How to reset a local variable during recursion?
有一个对象具有 "value" or/and "children" 作为属性。问题是将所有值和 return 相加。这是工作。我用过递归。我正在使用全局变量来存储总和。
请参考- https://jsfiddle.net/ws6ty78b/1/
function sumup(node) {
sum+=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sumup(node.children[i]);
}
}
return sum
}
问题 - 再次调用相同的函数时,我没有得到相同的结果。总和翻了一番。我知道为什么会这样,因为我使用的是全局变量。
问题 - 对于上述问题,有没有办法让我对任意次数的调用都得到相同的结果。
请注意限制-
1) 不要更改函数签名和声明。
2) 在'sumup'函数中使用'sum'变量。
3) 不要使用任何额外的变量。
4) 仅在 sumup 函数内进行更改。
为了实现您的目标,函数 sumup()
将被调用 N 次。我们不知道这个 N 是多少,因为它取决于子节点的递归次数。此外,由于限制,我们无法编辑函数签名,也无法在其他地方编写代码来做任何事情,甚至不能手动将 sum 设置为 0。
因此我们需要一种方法来区分一组调用和下一组调用,并重置它。
我的想法是我们设置一个阈值,使用closure。从第一次调用开始,在示例中,您有 5 秒的时间继续调用,之后它将重新开始。这真的是我们所能做的,除非提供另一种区分调用的方法。
编辑:我在这里尝试的是将所有递归保留为基本情况,而不更改对象。由于 OP 已经接受了该解决方案,我正在添加一个节点重置器 属性。如果任何节点的重置器未定义或为空、零或未定义,这将重置总和。我们必须假设它没有在启动对象中定义。正如我所说,这是一个薄弱的假设。通过在递归时定义它,结转当前总和。
为了最终的兴趣,我也会保留原来的时间门槛想法。
var obj = {
"value": 4,
"children": [
{
"value": 2,
"children": [
{
"value": 1
}
]
},
{
"value": 9
}
]
}
const sumup = (function(){
var lastTime = 0;
var newTime = 0;
var sum = 0;
const timeThreshold = 5000; // 5 seconds
return function(node) {
newTime = new Date().getTime();
if(!node["resetter"] || (newTime-lastTime >= timeThreshold)){
sum=0;
lastTime = newTime;
}
sum+=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sumup(Object.assign({"resetter":true},node.children[i]));
}
}
return sum;
}
})();
console.log(sumup(obj)); //16
console.log(sumup(obj)); //32! should print 16 everytime
您可以 call
在递归时进行求和,并 assign/test 针对自定义 this
:
var obj = {
"value": 4,
"children": [{
"value": 2,
"children": [{
"value": 1
}]
},
{
"value": 9
}
]
};
var sum = 0;
function sumup(node) {
//Only make change within this function body
if (!this || !this.recurse) sum = 0;
sum += node.value;
if (node.children && node.children.length > 0) {
for (var i = 0; i < node.children.length; i++) {
sumup.call({ recurse: true }, node.children[i]);
}
}
return sum
}
console.log(sumup(obj));
console.log(sumup(obj));
或者,您可以完全取消全局变量,而是对子项使用递归 reduce
:
var obj = {
"value": 4,
"children": [{
"value": 2,
"children": [{
"value": 1
}]
},
{
"value": 9
}
]
};
const sumup = (node) => (
node.value + (node.children
? node.children.reduce((a, child) => a + sumup(child), 0)
: 0
)
);
console.log(sumup(obj));
console.log(sumup(obj));
您可以简单地将每个子节点的值与当前节点的值相加:
function sumup(node) {
sum=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sum+=sumup(node.children[i]);
}
}
return sum
}
有一个对象具有 "value" or/and "children" 作为属性。问题是将所有值和 return 相加。这是工作。我用过递归。我正在使用全局变量来存储总和。
请参考- https://jsfiddle.net/ws6ty78b/1/
function sumup(node) {
sum+=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sumup(node.children[i]);
}
}
return sum
}
问题 - 再次调用相同的函数时,我没有得到相同的结果。总和翻了一番。我知道为什么会这样,因为我使用的是全局变量。
问题 - 对于上述问题,有没有办法让我对任意次数的调用都得到相同的结果。
请注意限制-
1) 不要更改函数签名和声明。
2) 在'sumup'函数中使用'sum'变量。
3) 不要使用任何额外的变量。
4) 仅在 sumup 函数内进行更改。
为了实现您的目标,函数 sumup()
将被调用 N 次。我们不知道这个 N 是多少,因为它取决于子节点的递归次数。此外,由于限制,我们无法编辑函数签名,也无法在其他地方编写代码来做任何事情,甚至不能手动将 sum 设置为 0。
因此我们需要一种方法来区分一组调用和下一组调用,并重置它。
我的想法是我们设置一个阈值,使用closure。从第一次调用开始,在示例中,您有 5 秒的时间继续调用,之后它将重新开始。这真的是我们所能做的,除非提供另一种区分调用的方法。
编辑:我在这里尝试的是将所有递归保留为基本情况,而不更改对象。由于 OP 已经接受了该解决方案,我正在添加一个节点重置器 属性。如果任何节点的重置器未定义或为空、零或未定义,这将重置总和。我们必须假设它没有在启动对象中定义。正如我所说,这是一个薄弱的假设。通过在递归时定义它,结转当前总和。 为了最终的兴趣,我也会保留原来的时间门槛想法。
var obj = {
"value": 4,
"children": [
{
"value": 2,
"children": [
{
"value": 1
}
]
},
{
"value": 9
}
]
}
const sumup = (function(){
var lastTime = 0;
var newTime = 0;
var sum = 0;
const timeThreshold = 5000; // 5 seconds
return function(node) {
newTime = new Date().getTime();
if(!node["resetter"] || (newTime-lastTime >= timeThreshold)){
sum=0;
lastTime = newTime;
}
sum+=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sumup(Object.assign({"resetter":true},node.children[i]));
}
}
return sum;
}
})();
console.log(sumup(obj)); //16
console.log(sumup(obj)); //32! should print 16 everytime
您可以 call
在递归时进行求和,并 assign/test 针对自定义 this
:
var obj = {
"value": 4,
"children": [{
"value": 2,
"children": [{
"value": 1
}]
},
{
"value": 9
}
]
};
var sum = 0;
function sumup(node) {
//Only make change within this function body
if (!this || !this.recurse) sum = 0;
sum += node.value;
if (node.children && node.children.length > 0) {
for (var i = 0; i < node.children.length; i++) {
sumup.call({ recurse: true }, node.children[i]);
}
}
return sum
}
console.log(sumup(obj));
console.log(sumup(obj));
或者,您可以完全取消全局变量,而是对子项使用递归 reduce
:
var obj = {
"value": 4,
"children": [{
"value": 2,
"children": [{
"value": 1
}]
},
{
"value": 9
}
]
};
const sumup = (node) => (
node.value + (node.children
? node.children.reduce((a, child) => a + sumup(child), 0)
: 0
)
);
console.log(sumup(obj));
console.log(sumup(obj));
您可以简单地将每个子节点的值与当前节点的值相加:
function sumup(node) {
sum=node.value;
if (node.children && node.children.length > 0) {
for (var i =0; i < node.children.length; i++) {
sum+=sumup(node.children[i]);
}
}
return sum
}