尾递归化简函数返回[...,[Curcular]]

时间:2018-08-18 02:19:19

标签: javascript node.js function recursion circular-reference

尝试编写一个reduce函数,该函数将过滤掉所有重复项。我知道还有其他方法可以解决此问题,但是我正在尝试练习递归函数。

function addToSet(a, b) {
  a.add(b);
  return a;
}

let set = new Set;

function reduce([head, ...last], fn, init) {
  if (head === undefined) return init;
  return fn(fn(init, head), reduce(last, fn, init))
}
const a = reduce([1, 2, 4, 6, 4, 3, 1, 2, 5, 1, 3, 4, 5, 7, 7], addToSet, set)

console.log(a)

// in node this returns // Set { 1, 2, 4, 6, 3, 5, 7, [Circular] }

我读到循环意味着对象是自引用的?但是我不确定我完全理解Set上下文的含义。为什么会有这个问题,我将如何解决? 非常感谢您的宝贵时间!

2 个答案:

答案 0 :(得分:2)

考虑这一点的一种好方法是仅查看addToSet的返回值。每次返回传入的集合。现在查看reduce的返回值。它返回刚建立的fn的结果,总是返回集合。

因此,您将reduce的结果传递到fn的第二个参数中时,会将集合传递给第二个参数fn,这会将集合添加到设置并给您一份圆形参考。

此:

 return fn(fn(init, head), reduce(last, fn, init))

最终成为:

 return fn(init, init)

解决起来并不难,因为没有真正的理由两次调用函数。您的基本情况将最终返回集合,因此您只需调用一次fn并返回reduce的结果即可。

function addToSet(a, b) {
    a.add(b);
  }
  
  let set = new Set;
  
  function reduce([head, ...last], fn, init) {
    if (head === undefined) return init
    fn(init, head)
    return reduce(last, fn, init)
  }
  const a = reduce([1, 2, 4, 6, 4, 3, 1, 2, 5, 1, 3, 4, 5, 7, 7], addToSet, set)
  
 console.log([...a]) // spreading because sets don't print here
  

答案 1 :(得分:1)

要弄清楚这里发生了什么,我们可以在您的递归函数中放置一个控制台日志,并使用如下这样的小集来运行它:

function addToSet(a, b) {
  a.add(b);
  return a;
}

let set = new Set;

function reduce([head, ...last], fn, init) {
  console.log("head", head)
  console.log("last", last)
  console.log("init", init)
  if (head === undefined) return init;
  return fn(fn(init, head), reduce(last, fn, init))
}
const a = reduce([2, 4, 4], addToSet, set)

console.log(a)

我们得到此输出(请记住,最后一行是最后一次调用返回的内容)

enter image description here

如您所见,您最后一次在空数组上调用递归函数,然后在其中返回init,并将其添加到集合的末尾。您可能想通过修改基本案例来解决这一问题。我会把它留给您找出答案,但是如果您需要更多帮助,可以随时发表评论。

又有一个想法:

考虑递归就像说该函数的一次运行将负责一个动作/计算/步骤/无论您想如何考虑。问问自己那一步是什么。

Ex:

如果我是一个函数调用,也许我只想对以下问题负责:“我是否将当前的head添加到init?”

有很多方法可以做到这一点,但也许一种方法是说(用伪代码):

reduce([head, ...last], fn, init) {
  is_base_case (where head is undefined)?
    return // do nothing -- we don't want undefined to be in the set
  otherwise
    attempt to add head to init
  reduce(...) // call the next reduce fn -- responsible for the next head
  return init // init should either have the original set or the set + head
}

这并没有说明undefined实际上是数组中的一个值,但希望它能说明这个概念。