Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaScript filter() method confusion

Tags:

javascript

I'm working through JavaScript: The Definitive Guide as part of Learn JavaScript Properly, and I'm having trouble reasoning about the filter() method in Chapter 7's section on Array Methods.

Here's the example provided:

The filter() method returns an array containing a subset of the elements of the array on which it is invoked. The function you pass to it should be predicate: a function that returns true or false. The predicate is invoked just as for forEach() and map(). If the return value is true, or a value that converts to true, then the element passed to the predicate is a member of the subset and is added to the array that will become the return value.

Examples:

a = [5, 4, 3, 2, 1];
smallvalues = a.filter(function(x) { return x < 3 });   // [2, 1]
everyother = a.filter(function(x,i) { return i%2==0 }); // [5, 3, 1] 

Where I'm getting confused is how exactly i is applied to x in the the everyother line. Here's what I think is happening:

  1. i (the index of a[]) is being passed through the function ,x, which applies the predicate to each element of a[] and returns [4, 2].

  2. Then the function says "filter [4, 2] out of a[]"...I'm real fuzzy on how.

When I mess around in the console, I've tried:

everyother = a.filter(function(i) { return i%2==0 });  // returns [4, 2]

which is what I would expect, but I don't understand what happens internally in how JS handles the parameters when I change the above code to

everyother = a.filter(function(x,i) { return i%2==0 }); // returns [5, 3, 1]

(I do know that the array methods are applied like so: function(element, index, array))

For this particular example, it's obvious to me that I could get the expected result another way:

everyother = a.filter(function(x) { return x%2!=0 }); // returns [5, 3, 1]

But I suspect that line of thinking is precisely missing the point the example is trying to get across...I'm just missing it.

like image 660
benvenker Avatar asked Aug 30 '14 18:08

benvenker


4 Answers

Your example is really simple and clear:

a = [5, 4, 3, 2, 1];
smallvalues = a.filter(function(x) { return x < 3 });   // [2, 1]
everyother = a.filter(function(x,i) { return i%2==0 }); // [5, 3, 1]

The first one reads: »return me every element (x), which is lesser than 3«. The result is not astounding.

The second one reads: »return me every element, whose index (i) is even (including 0)«

The x is just ignored.

You could also have written [5, 4, 3, 2, 1].filter(function(_,x){return x%2===0})

See MDN for Array.prototype.filter().

like image 55
Thomas Junk Avatar answered Oct 31 '22 12:10

Thomas Junk


When you invoke filter with a function of two arguments, the first argument binds to the array element value, the second (the optional one) to the element index.

Your confusion stems from the fact that the input array [5,4,3,2,1] is somewhat specific - elements that have even indexes (5, 3, 1) are odd and elements that have odd indexes (4, 2) are even.

This makes this filtering predicate ...%2 always pick elements of the same 'kind', depending on what you pass as the predicate parameter (value or index) you will get odd or even elements.

My advice to clean up the confusion would be to pick a different array to test your filtering method. The array should mix oddity of indexes and values, something like [1,3,4,5,7,8]. You will immediately observe what happens when the predicate takes a value or an index into account.

Also remember that when creating a filtering predicate, the names of formal parameters are arbitrary, what matters is their position. The first parameter, no matter how you call it, stands for the value, the second stands for the index. If you clash your parameter names by accident and you call your first parameter i and then your second parameter i then it binds to something else in both scenarios.

like image 7
Wiktor Zychla Avatar answered Oct 31 '22 13:10

Wiktor Zychla


a = [5, 4, 3, 2, 1];
everyother = a.filter(function(x,i) { return i%2==0 }); // [5, 3, 1] 

x is each element in the array .(first iteration x = 5, second iteration x=4 , so on..)
i is the index - (first iteration i = 0, second iteration i=1 , so on..)

So, in the question (for first iteration-i% 2 becomes 0%2 which is equal to 0 and the condition becomes true. And the first element is returned to the array ..hence 5 is returned,). next, 1%2 !=0, so 4 gets removed. 2%2 ==0, hence 3 stays. (so on..)

In this syntax :- x is having a value for each iteration, but it isn't used up in the condition.

Tip: filter() always expects a boolean value.and whatever gets returned (true or false) determines whether the value(or element) stays in the array or not.

like image 1
user8182798 Avatar answered Oct 31 '22 14:10

user8182798


Its simple... In everyother, i is the index of each element and the only possible values of i are 0,1,2,3,4 as you have five elements in array.

Now out of all values of i only 0,2,4 are divisible by 2 and that's why you are getting values of those indices i.e [5,3,1].

like image 1
Nitesh Ranjan Avatar answered Oct 31 '22 14:10

Nitesh Ranjan