[英]Tail recursive reduce function returns […, [Curcular] ]
尝试编写一个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上下文的含义。 为什么会有这个问题,我将如何解决? 非常感谢您的宝贵时间!
考虑这一点的一种好方法是仅查看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
为了弄清楚这里发生了什么,我们可以在您的递归函数中放置一个控制台日志,并使用如下这样的小集来运行它:
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)
我们得到此输出(请记住,最后一行是从最后一次调用返回的内容)
如您所见,您最后一次在空数组上调用递归函数,然后在其中返回init,并将其添加到集合的末尾。 您可能想通过修改基本案例来解决这一问题。 我将其留给您练习,但是如果您需要更多帮助,可以随时提出反馈。
还有一个想法:
考虑到递归就像说函数的一次运行将负责一个动作/计算/步骤/无论您想考虑什么。 问问自己那一步是什么。
例如:
如果我是一个函数调用,也许我只想对以下问题负责:“我是否将当前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实际上是数组中的一个值,但希望它能说明这个概念。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.