I wrote a function that flatten and array.
const multiArray = [1, [2, 3, [4, [5]]], 6, [7, 8, 9, [10]]]
let newArray = []
const flatenArray = (params) => {
params.map((sm) => {
if(Array.isArray(sm)) {
return flatenArray(sm)
}
newArray.push(sm);
})
return newArray
}
//console.log(flatenArray(multiArray)) result [1,2,3,4,5,6,7,8,9,10]
The above function works fine.
but if I remove the return keyword from the "if" block then does it returns something else?
let newArray2 = []
const flatenArray2 = (params) => {
params.map((sm) => {
if(Array.isArray(sm)) {
flatenArray(sm)
}
newArray2.push(sm);
})
return newArray2
}
console.log(flatenArray2(multiArray))
//result [1,[2,3,[4,[5]]],6,[7,8,9,[10]]]
Now I would like to know...
Why should I use the return keyword there even when I'm calling it?
What is happening when I use the return keyword there?
CodePudding user response:
What is happening when I use the
return
keyword there?
The function (the callback that you're passing to map
) does return a value and stop executing. This means it will not reach the next line, newArray.push(sm);
, after the if
statement, which does push the sm
array onto the result array in your second implementation.
Why should I use the
return
keyword there even when I'm calling it?
You shouldn't actually. Using an else
statement would be much cleaner (and also you shouldn't abuse map
):
const flattenArray = (params) => {
for (const sm of params) {
if (Array.isArray(sm)) {
flattenArray(sm)
} else {
newArray.push(sm);
}
}
return newArray
}
CodePudding user response:
Every function has to "return" something, and that's result value of your function!
Imagine a sum function without a return value!
const noreturn_sum = (a, b) => {
a b
}
if you don't return something, your function returns undefined
implicitly.
so if you gonna print the result of noreturn_sum
, you will get:
console.log(noreturn_sum(1, 2))
>> undefined
This is true even in your example, let me explain : (may I cleanup your code a little bit?)
let newArray2 = []
const flatenArray2 = (params) => {
// PART 1 ---------
params.map((sm) => {
if(Array.isArray(sm)) {
flatenArray(sm) // PART 1.map.fn ---------
}
newArray2.push(sm);
})
// END PART 1 ---------
// PART 2 ---------
return newArray2
// END PART 2 ---------
}
console.log(flatenArray2(multiArray))
A. your function for each parameter does this:
- checks if it's an array:
true => call the function again to reach to a non-array value
false [it's a value] => add it to newArray2
- then returns
undefined
B. then your whole params.map(...
returns an array of undefined
, because your function inside map (that I explained it in (1.) and (2.) returns undefined
C. you return newArray2
at the end of the function.
note that your flatenArray2
function always return the newArray2
but inside "PART 1.map.fn" you "discard" it (or you "ignore" it in other words)
but in the last experssion console.log(flatenArray2(multiArray))
you gave the returned value to the console.log
function.
CodePudding user response:
When you do not use the result, either by assigning, passing or returning, you are solely relying on the side effects on the function.
Eg. in your flatenArray
if you pass it a [[1]]
sm
will be [1]
, thus the if test is true
and it will recurse with [1]
. It will then fail on the test because 1
is not an array and push 1
to newArray
. It then returns newArray
which is then instantly returned and no more of that function is used in that round. You never use the resulting array from map
since you are never ever returning this so one could question why you didn't use forEach
instead to enforce that it is just for side effects (mutating newArray
). If you were to remove return
it will continue down and do newArray.push(sm)
even though it is an array Thus you would get both flattened results and unflattened results in the result array mixed and doubled up. This could be prevented by having the last statement in an else
so that the function either did the array thing or the element thing.
The flatenArray2
doesn't recurse as it uses flatenArray
that populates newArray
and not newArray2
so it will only make a shallow copy of the original array due to the flattened elements being added to newArray
and the unflattened elements being added to newArray2
which is the only result that is returned.
If you were to call any function twice you will get the results of the previous runs in the second.
This is how I would have made it to prevent it from keeping results from previous rounds and actually using the results returned:
const multiArray = [1, [2, 3, [4, [5]]], 6, [7, 8, 9, [10]]];
const flattenPure = (arr) => {
const helper = (acc, e) =>
Array.isArray(e)
? e.reduce(helper, acc) // reduce the array e with acc as accumulator
: [...acc, e]; // make a new array with elements from acc and the element e
return arr.reduce(helper, []); // start with an empty accumulator
}
console.log("Once Pure", flattenPure(multiArray));
console.log("Twice Pure", flattenPure(multiArray));
Using Array.proptype.push
makes a faster version, however then why not just use Array.prototype.flatten)?
const multiArray = [1, [2, 3, [4, [5]]], 6, [7, 8, 9, [10]]];
const flattenSide = (arr) => {
let res = []; // this is new every time flatten is called
const helper = (e) => {
if (Array.isArray(e)) {
e.forEach(helper); // indirect recurse for each element
} else {
res.push(e);
}
// hidden return undefined here
};
helper(arr); // flatten arr with result in res
return res; // return result
}
console.log("Once Side", flattenSide(multiArray));
console.log("Twice Side", flattenSide(multiArray));