繁体   English   中英

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

[英]How to prevent a recursive function from re-initializing an accumulating variable?

这个函数是用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:我知道这可以通过将累积数组从函数中拉出到另一个范围来“解决”,但这会导致其他问题,例如每次运行函数之前需要重新初始化累积数组它不止一次。)

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

你真正的问题是:

uniteUnique(...item);

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

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

if (Array.isArray(item)) {

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

另一种可能性是将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);

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

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

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 for seenBefore ,因为Array.prototype.includes扫描数组,这是无效的。

以防万一:如果您可以使用最新的ES2019功能并且更喜欢简单,这也可以通过单线程实现:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM