JavaScript - Как сбросить локальную переменную во время рекурсии? - PullRequest
0 голосов
/ 12 мая 2018

Существует объект со значением "value" или / и "children" в качестве свойств.Проблема состоит в том, чтобы сложить все значения и вернуть сумму.Это работает.Я использовал рекурсию.Я использую глобальную переменную для хранения суммы.

Пожалуйста, обратитесь - 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) Используйте переменную sum внутри функции sumup.

3) Не используйте никаких дополнительных переменных.

4) Вносите изменения только в функцию суммирования.

Ответы [ 3 ]

0 голосов
/ 12 мая 2018

Вы можете call суммировать во время рекурсии и назначать / проверять пользовательский 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));
0 голосов
/ 12 мая 2018

Вы можете просто суммировать значения каждого потомка со значением текущего узла:

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
    }
0 голосов
/ 12 мая 2018

Для достижения вашей цели функция sumup() будет вызываться N раз.Мы не знаем, сколько это N, так как оно зависит от количества рекурсий для дочерних узлов.Кроме того, благодаря ограничениям, мы не можем редактировать сигнатуру функции и не можем писать код в другом месте, чтобы делать что-либо, даже не устанавливая сумму вручную в 0.

Поэтому нам нужен способ различатьнабор вызовов из NEXT связки и сбросьте его.

Моя идея состоит в том, что мы устанавливаем порог, используем замыкание .Начиная с первого вызова, в этом примере у вас есть 5 секунд времени для продолжения вызова, после чего он начнется заново.Это действительно все, что мы можем сделать, если не предусмотрен другой способ различения вызовов.

РЕДАКТИРОВАТЬ: То, что я пытался здесь, это сохранить все рекурсии как базовый вариант, а не изменять объект.Так как OP принял это решение, я добавляю свойство resetter узла.Если в каком-либо узле есть средство сброса, которое не определено, или ноль, или ноль, или не определено, это сбросит сумму.Мы должны предположить, что это не определено в запущенном объекте.Как я уже сказал, это довольно слабое предположение.Определяя его при повторении, текущая сумма переносится.Я также сохраню первоначальную идею о пороге времени для возможного интереса.

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
...