Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply variable number of filter conditions to a javascript array while traversing it only once?

I have a javascript array of nested data that holds data which will be displayed to the user.

The user would like to be able to apply 0 to n filter conditions to the data they are looking at.

In order to meet this goal, I need to first find elements that match the 0 to n filter conditions, then perform some data manipulation on those entries. An obvious way of solving this is to have several filter statements back to back (with a conditional check inside them to see if the filter needs to be applied) and then a map function at the end like this:

var firstFilterList = _.filter(myData, firstFilterFunction);
var secondFilterList = _.filter(firstFilterList, secondFilterFunction);
var thirdFilterList = _.filter(secondFilterList, thirdFilterFunction);
var finalList = _.map(thirdFilterList, postFilterFunction);

In this case however, the javascript array would be traversed 4 times. A way to get around this would be to have a single filter that checks all 3 (or 0 to n) conditions before determining if there is a match, and then, inside the filter at the end of the function, doing the data manipulation, however this seems a bit hacky and makes the "filter" responsible for more than one thing, which is not ideal. The upside would be that the javascript Array is traversed only once.

Is there a "best practices" way of doing what I am trying to accomplish?

EDIT: I am also interested in hearing if it is considered bad practice to perform data manipulation (adding fields to javascript objects etc...) within a filter function.

like image 256
B. Smith Avatar asked Oct 16 '25 15:10

B. Smith


2 Answers

You could collect all filter functions in an array and check every filter with the actual data set and filter by the result. Then take your mapping function to get the wanted result.

var data = [ /* ... */ ],
    filterFn1 = () => Math.round(Math.random()),
    filterFn2 = (age) => age > 35,
    filterFn3 = year => year === 1955,
    fns = [filterFn1, filterFn2, filterFn2],
    whatever = ... // final function for mapping
    result = data
        .filter(x => fns.every(f => f(x)))
        .map(whatever);
like image 199
Nina Scholz Avatar answered Oct 18 '25 07:10

Nina Scholz


One thing you can do is to combine all those filter functions into one single function, with reduce, then call filter with the combined function.

var combined = [firstFilterFunction, seconfFilterFunction, ...]
                .reduce((x, y) => (z => x(z) && y(z)));
var filtered = myData.filter(combined);
like image 39
Sweeper Avatar answered Oct 18 '25 06:10

Sweeper



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!