如何防止递归函数重新初始化累加变量?

时间:2019-01-29 00:38:53

标签: javascript variables recursion

此函数是用JavaScript编写的,但我认为可以用其他一些编程语言来实现该概念。

function uniteUnique(arr) {
    let seenBefore = []; //the accumulating array
    for (let item of arguments) {
        if (typeof (item) == "object") {
            uniteUnique(...item);
        }
        else if (!seenBefore.includes(item)) {
            seenBefore.push(item);
        }
    }
    return seenBefore;
}
简而言之,该函数对作为参数接收的数组进行迭代,而数组本身可能包含也可能不包含其他数组。这些数组中最深的级别包含int值。该函数返回一个包含所有int(即出现在嵌套数组中的数组)的数组,但是即使每个int出现了多次,它也只返回一次。

我的问题在于,每次递归返回到更高的级别时,它都会再次初始化包含保存的int的数组,即函数需要的数组返回(seenBefore,从而破坏了整个过程。一方面,我必须在函数启动时初始化数组,但另一方面,它会被多次初始化并丢失其先前存储的值。

例如,如果我要运行函数

uniteUnique([1, 3, [6, 3], 2], [5, 2, 1, 4], [2, 1]);

输出应为

[1,3,6,2,5,4]

因为该函数必须按处理顺序仅返回一次偶然发现的数字。该函数实际上返回一个空数组,因为在从最高级别的递归返回该函数之前,它已再次初始化。

如何绕过此问题?

(PS:我知道可以通过将累积数组从函数中拉到另一个作用域来“解决”,但这会引起其他问题,例如每次运行函数之前都需要重新初始化累积数组如果我多次运行它。)

4 个答案:

答案 0 :(得分:3)

您误认了您的问题。每次对uniteUnique()的调用都有一个局部变量seenBefore的单独值-递归调用期间没有“再次初始化”。

您真正的问题是该行:

uniteUnique(...item);

放弃该函数调用的结果,因此将忽略任何嵌套数组的内容。您需要在某个地方分配此函数的返回值并使用它。

您可能还希望将此函数调用的条件更改为:

if (Array.isArray(item)) {

因为当前条件typeof item == "object"将包含无法迭代的对象。

答案 1 :(得分:3)

另一种可能性是将seenBefore定义为空数组作为默认的第二个参数,该数组递归传递给函数的每次调用:

function uniteUnique(arr, seenBefore = []) {
  for (const item of arr) {
    if (typeof (item) == "object") {
      uniteUnique(item, seenBefore);
    }
    else if (!seenBefore.includes(item)) {
      seenBefore.push(item);
    }
  }
  return seenBefore;
}

uniteUnique(someArr);

请注意,它接受单个参数作为数组,而不是多个参数。

答案 2 :(得分:1)

您可以利用嵌套函数,这样就不必每次都重新初始化累积数组:

SELECT title
       FROM film_list
       WHERE char_length(title) = 8;

您实际上不需要在这里使用function uniteUnique(arr) { function iterate(seenBefore, arr) { for (let item of arr) { if (Array.isArray(item)) { iterate(seenBefore, item); } else if (!seenBefore.includes(item)) { seenBefore.push(item); } } } let result = []; // the accumulating array iterate(result, arr); return result ; } 和散布运算符,因为您的函数需要一个数组,并且您可以简单地传递一个数组。

您可能还想将arguments用于Set,因为seenBefore扫描整个数组是无效的。

答案 3 :(得分:0)

以防万一:如果您可以使用最新的ES2019功能并偏爱简单性,也可以使用单线实现:

const uniquesArray = [...new Set(nestedArray.flat(Infinity))];