Performance question about to write higher order arrow functions

Dear campers.
In this section “Write Higher Order Arrow Functions”
with link https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/write-higher-order-arrow-functions
My solution was

arr.map((num) => parseInt(num) == num && num >= 0 ? num * num : null ).filter((num) => num !== null);

And the FCC’s solution is

arr.filter( (num) => num > 0 && num % parseInt(num) === 0 ).map( (num) => Math.pow(num, 2) );

I think the second (FCC’s) solution is better for performance.

What do you think about it ? What do you want to say ?

Hey,

If you take into account that we have an array [1, -2, 3]

By doing the filter first you will remove whichever number are lower than 0 so you will end up with [1, 3] for the map to iterate. (FCC’s solution)

By doing the map first you will be sending to the filter [1, null, 9] which will then be passed to the filter to iterate. (Your solution)

On FCC solution you will loop through an array of length 3 and then trough an array of length 2 so, 5 iterations.

On your solution you will loop through an array of length 3 and then again through length 3 so, 6 iterations.

The less iterations the better, as long as you keep readability of the code.

Note that it can happen for the FCC solution to iterate the same times as your solution either way depending on our array, the important part is that it will iterate less in some scenarios while your solution will always iterate all of the array length twice

Hello @daspinola
I did a small test between the 2 solutions and you’re correct :slight_smile:

I wrote a function which creating a random array with N values where each value 65% is positive and randomly can be a float or integer.

let arr = [];

const createArr = (numCount) =>
{
    let from = -10;
    let to  = 10;    
    let diff = to - from;           
    
    for(let i=0;i<numCount;i++){
        let num = ( Math.random() * diff + 1) + from;        
        if(Math.random() < 0.85){            
            arr.push(Math.round(num));
        } else {
            arr.push(parseFloat(parseFloat(num).toFixed(2)));
        }
    }
    
}
createArr(100000);

After the creation I did the following test with hrtime

let start = process.hrtime();
//FCC
let intPows = arr.filter( (num) => num > 0 && num % parseInt(num) === 0 ).map( (num) => Math.pow(num, 2) );
let end = process.hrtime(start);
console.info('FCC = : %ds %dms', end[0], end[1] / 1000000);
//Mine
start = process.hrtime();
let intPows2 = arr.map((num) => parseInt(num) == num && num >= 0 ? num * num : null ).filter((num) => num !== null);
end = process.hrtime(start);
console.info('Mine = : %ds %dms', end[0], end[1] / 1000000);

And here is the result for 1000000 items

FCC = : 0s 4.9151ms
Mine = : 0s 13.982999ms

1 Like

If this were a stream or a transducer you could do it all in one sweep tbh. But since this is a library-free environment, you have to manually represent it as a reduce statement:

const filterMap = (pred, mapper, xs) => xs.reduce((result, x) => {
  if (pred(x)) result.push(mapper(x))

  return result
}, [])

Reduce can do anything, but in this case you can also use flatMap:

xs.flatMap((x) => pred(x) ? [mapper(x)] : [])

(for illustration – usually it’s the mapper() function that returns the array instead of wrapping it up here)

1 Like