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 int
s (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 int
s, 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 int
s (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 int
s, 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 badges4 Answers
Reset to default 3You'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条)