Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best way to create simple filter functions in javascript?

Many times I face the same problem: I want to filter an array with a simple condition e.g. check for non/equality, greater than, less than, contains...

My code looks like this:

var result = [1, 2, 3, 4].filter(function(i) {
   return i > 2; 
});
console.log(result); // [3, 4]

It would by nice to have shortcuts to such a simple operations so I created some helper functions:

function isGreaterThan(value) {
    return function(original) {
        return value < original;
    }
}
[1, 2, 3, 4].filter(isGreaterThan(2)); // [3, 4]

or:

function isGreaterThan(value, original) {
    return value < original;
}
[1, 2, 3, 4].filter(isGreaterThan.bind(null, 2)); // [3, 4]

Is there a better way how to do this in javascript? Does javascript have any built-in functions to support these simple comparisions?

like image 210
madox2 Avatar asked Dec 20 '15 18:12

madox2


2 Answers

Madox, what you've stumbled upon is the concept of currying! And you'll be glad to hear that there is an entire JavaScript community built around that idea. With Ramda your code would look like:

var filterSmallNumbers = filter(gte(3));
var smallNumbers = filterSmallNumbers([1,2,3,4,5,6]);

And it works.

All Ramda provides, is a list of "curried helper functions" like the one you showed. If you'd rather curry your own helper functions, then you might want a curry helper function which reduces the boilerplate: var isGreaterThan = curry(function(a, b){ return a > b }). This curry function is provided by most utility libraries like Underscore, Lodash or Ramda.

like image 114
Avaq Avatar answered Oct 25 '22 07:10

Avaq


I'll expand on @Avaq's answer a little bit here. You don't need a lib like Rambda to start using currying. You can start doing this with ES6 today.

It seems you already understand the concept here. This is already a curried function. (Each sequenced function takes only one argument)

function isGreaterThan(value) {
    return function(original) {
        return value < original;
    }
}

With ES6 arrow functions, this gets a lot easier.

const gt = x => y => y > x;

Notice how you flipped the the operator > to a < in your function to make the usage seem more natural? It's very common with curried functions to first take the operand that is least likely to change. With gt, I think it's better to use > here since that's the name of our function, but instead flip the operands. That's why you see me returning y > x instead of x > y. gt(5) returns a function y => y > 5, which feels very natural to me.

Without further ado, let's see it work in a filter

[1,2,3,4,5,6].filter(gt(3)); //=> [4,5,6]

If you need this to work in an ES5 environment, you can transpile it with babel very easily. The result should look very familiar

"use strict";
var gt = function gt(x) {
    return function (y) {
        return y > x;
    };
};

And with that, you're at the doorstep of functional programming. There's a ton of fun stuff to learn. With the kind of problem we discussed here, I think you'd be interested in learning about function composition next.

Here's a basic composition to whet your appetite

// filter out odd numbers
const mod = x => y => y % x;
const eq = x => y => y === x;
const comp = f => g => x => f(g(x));
const isEven = comp (eq (0)) (mod (2));
[1,2,3,4,5,6].filter(isEven); //=> [2,4,6]
like image 27
Mulan Avatar answered Oct 25 '22 07:10

Mulan