javascript - How to prevent a recursive function from re-initializing an accumulating variable? - Stack Overflow

This function is written in JavaScript but I think that the concept can be implemented with some other

This function is written in JavaScript but I think that the concept can be implemented with some other programming languages.

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;
}

In short, the function iterates over arrays it receives as arguments, which may or may not contain other arrays themselves. the deepest level of any of those arrays contains int values. The function returns an array that contains all those ints (i.e those that appeared in nested arrays), but it returns each int only once, even if it appeared more than one time.

My problem lies in the fact that every time the recursion returns to a higher level, it initializes again the array that contains the saved ints, namely the array that the function needs to return (seenBefore), and therefore ruins the whole process. On one hand, I must initialize the array when the function starts, but on the other hand, it is initialized more than once and loses its previously stored values.

for example, if I would run the function

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

the output should be

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

because the function has to return the numbers it stumble upon only once by the order of processing. The function actually returns an empty array because it is initialized again right before the function returns from the top-most level of the recursion.

How can I bypass this problem?

(P.S: I know this can be "solved" by pulling the accumulating array out of the function to a different scope, but that causes other problems, such as the need to reinitialize the accumulating array each time before I run the function if I run it more than once.)

This function is written in JavaScript but I think that the concept can be implemented with some other programming languages.

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;
}

In short, the function iterates over arrays it receives as arguments, which may or may not contain other arrays themselves. the deepest level of any of those arrays contains int values. The function returns an array that contains all those ints (i.e those that appeared in nested arrays), but it returns each int only once, even if it appeared more than one time.

My problem lies in the fact that every time the recursion returns to a higher level, it initializes again the array that contains the saved ints, namely the array that the function needs to return (seenBefore), and therefore ruins the whole process. On one hand, I must initialize the array when the function starts, but on the other hand, it is initialized more than once and loses its previously stored values.

for example, if I would run the function

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

the output should be

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

because the function has to return the numbers it stumble upon only once by the order of processing. The function actually returns an empty array because it is initialized again right before the function returns from the top-most level of the recursion.

How can I bypass this problem?

(P.S: I know this can be "solved" by pulling the accumulating array out of the function to a different scope, but that causes other problems, such as the need to reinitialize the accumulating array each time before I run the function if I run it more than once.)

Share Improve this question asked Jan 29, 2019 at 0:38 Yoav VollanskyYoav Vollansky 2034 silver badges13 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 3

You've misidentified your problem. Each call to uniteUnique() has a separate value for the local variable seenBefore -- nothing is being "initialized again" during recursive calls.

Your real problem is that the line:

uniteUnique(...item);

discards the result of that function call, so the contents of any nested arrays are ignored. You need to assign the return value of this function somewhere and use it.

You may also want to change the condition for this function call to:

if (Array.isArray(item)) {

as the current condition typeof item == "object" will include objects which cannot be iterated over.

Another possibility would be to define seenBefore as the empty array as a default second parameter, which is recursively passed to every call of the function:

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);

Note that this accepts a single argument as an array, rather than multiple arguments.

You can utilize a nested function, so that you don't need to reinitialize the accumulating array each time:

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 ;
}

You don't actually need to use arguments and spread operator here, because your function expects an array and you can simply pass an array.

You may also want to use Set for seenBefore, because Array.prototype.includes scans through an array, which is ineffective.

Just in case: if you can use the last ES2019 features and prefer simplicity, this can also be achieved with a one-liner:

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

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744395788a4572131.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信