Reputation: 25
I'm doing FreeCodeCamp tasks, and now I get stuck with Arrow Function Problem is : I need to sort an array(which "filter" function doing well - it sorts) but my map. function doesnt work. I get an error "((num > 0) && Number.isInteger(...)).map is not a function"
Thanks in advance
const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2];
const squareList = (arr) => {
"use strict";
const squaredIntegers = arr.filter((num) =>
(num > 0 && Number.isInteger(num)).map((num) => Math.pow(num,2) ))
return squaredIntegers;
};
It should return an array the square of only the positive integers.
Upvotes: 0
Views: 281
Reputation: 1
const realNumberArray = [4,5.6,-9.8,3.14,42,6,8.34,-2];
const squareList = (arr) => {
const squaredIntegers = arr.filter(num => typeof num ==="number" &&
isFinite(num) && Math.floor(num) === num && num>0).map(num => num ** 2)
return squaredIntegers;
};
const squaredIntegers = squareList(realNumberArray);
console.log(squaredIntegers);
Upvotes: 0
Reputation: 135247
But you said higher-order arrow functions ^_^
const squareList = arr =>
$ (arr) // beginning with arr,
(filter (num => num > 0)) // filter
(filter (Number.isInteger)) // filter some more
(map (x => x ** 2)) // map
($) // extract result
const map = f => xs =>
xs .map (x => f (x)) // Array.prototype.map
const filter = f => xs =>
xs .filter (x => f (x)) // Array.prototype.filter
const $ = x => // beginning with x,
f => // and a function, f,
f === $ // exit condition
? x // return x
: $ (f (x)) // otherwise, transform x using f and recur
const realNumbers =
[ 4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2 ]
const result =
squareList (realNumbers)
console.log(result)
// [ 16, 1764, 36 ]
Functions like $
allow us to think about our problem in different ways. Above we see squareList
take an array and pass it down the "pipe" vertically. Intuitively, it's nice to think about the problem as sequence of arr->filter->filter->map
but this is a wasteful computation. As others have pointed out, it can be done with a single reduce
. Wouldn't it be nice if we could have our cake and eat it too?
Functional programming is all about programming with functions. This doesn't mean we have to forfeit writing programs in a particular way. Simply write functions to isolate complexity and do the hard work for you.
Below, squareList
is exactly the same as above, but this time we change the program's behaviour dramatically by refactoring $
. Instead of running filter->filter->map
in sequence, this version builds up a pending computation and runs a single reduce
when the value is popped out. A popular name for this technique is transducers; here I've encoded them using arrow functions.
Higher-order arrow functions for days ^_^
const squareList = arr =>
$ (arr) // beginning with arr,
(filter (num => num > 0)) // add filter transducer
(filter (Number.isInteger)) // add another filter transducer
(map (x => x ** 2)) // add map transducer
($) // run transducer
const map = f => // map transducer
k => (r, x) => k (r, f (x))
const filter = f => // filter transducer
k => (r, x) => f (x) ? k (r, x) : r
const $ = (x, t = identity) => // beginning with x and base transducer,
f => // and a function, f,
f === $ // exit condition
? x .reduce (t (push), []) // run transducer; single reduce
: $ (x, comp (t, f)) // otherwise, recur with new transducer
const identity = x =>
x
const push = (r, x) =>
( r .push (x)
, r
)
const comp = (f, g) =>
x => f (g (x))
const realNumbers =
[ 4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2 ]
const result =
squareList (realNumbers)
console.log(result)
// [ 16, 1764, 36 ]
Above $
only iterates over the input array once, compared to filter->filter->map
which iterates over the input array three (3) times. This is a big performance gain in scenarios where arr
is significantly large.
$
could be anything – and because it's a function, it gives us a domain we can control and make meaningful changes; maybe we make some performance optimisations; maybe it could throw a TypeError
if an invalid argument is given; maybe we call it pipe
or call it trans
or whatever. Don't get stuck thinking functional programming begins and ends at Array.prototype.map
, Array.prototype.filter
, Array.prototype.reduce
et al. You imagine the magic wand and you create it ^_^
Upvotes: 0
Reputation: 769
You can do this using only reduce function.
const list = [4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2];
const result = list.reduce((acc, val) => {
if (Number.isInteger(val) && val > 0) {acc.push(val*val)};
return acc;
}, []);
console.log(result);
Upvotes: 0
Reputation: 1032
You can do everything together without using return
or setting to another const:
const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2];
const squareList = (arr) => arr.filter(num => num > 0 &&
Number.isInteger(num)).map(num => Math.pow(num,2));
Upvotes: 1
Reputation: 370799
Put the .map
after the .filter
is completely done:
const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2];
const squareList = (arr) => {
return arr
.filter(num => num > 0 && Number.isInteger(num))
.map(num => num ** 2)
};
console.log(squareList(realNumberArray));
Upvotes: 2