Antonio
Antonio

Reputation: 654

Strange behavior of filter and map in javascript

I need to write a code that gets an array of integer and return an array with element increased if it's even and decreased if is odd. I tried with filter and map JavaScript functions. Here it is the code:

var test=[2,5,8,13];
var my_function = (some_array) => some_array.filter((num,index,array) => num % 2 == 0 ? array[index]=num+1 : array[index]=num-1 );
console.log(my_function(test));
console.log(test);

this code prints [2, 5, 8, 13] [3, 4, 9, 12] while using a map you have

var test=[2,5,8,13];

var my_function = (some_array) => some_array.map((num,index,array) => num % 2 == 0 ? array[index]=num+1 : array[index]=num-1 );
console.log(my_function(test));
console.log(test);

this code prints [3, 4, 9, 12] [3, 4, 9, 12]

As you can see with filter the object is cloned while with map the object is changed. The documentation on MDN says:

The map() method creates a new array with the results of calling a provided function on every element in this array.

Am I using the map and filter in a wrong way or the documentation is wrong? I tested this behavior on chrome and firefox.

Actually I was using wrong the map function. Here is the map code fixed

var my_function = (some_array) => some_array.map((num) => num % 2 == 0 ? num+1 : num-1 );

Upvotes: 0

Views: 349

Answers (3)

Jonas Høgh
Jonas Høgh

Reputation: 10874

You're both mutating the array through the reference passed as the third parameter in the lambda ("array") and returning a new array through the return values from the lambda. Map and filter are usually used in a functional style where the array is not mutated, but a new array is created and returned from the functions.

You want to use map here not filter. While your current filter implementation does what you want, the idiomatic way to use filter is to input one array, and return a new array which contains a subset of the elements in the first array, namely the elements that fulfill the predicate represented by the passed function.

The idiomatic way to use map is to input one array, and return a new array which has the same length as the first array, but has some function applied to each of the original elements. This is what you want, and your function should simply test for odd/even then return n-1 or n+1 respectively.

Upvotes: 2

MartijnK
MartijnK

Reputation: 672

To do what you want, you can use map like this:

var result = test.map(function(m){ return m % 2 === 0 ? m+1 : m-1 });
console.log(result);

Filter is also possible, but personally, I'd prefer map. Just keep in mind that map returns a new array with the result. Be careful not to change you original array.

Upvotes: -1

matanso
matanso

Reputation: 1292

You are using them wrong. Filter gets a function that returns a Boolean and leaves only the elements in the array for which that function returns true. What happened here is that when you used arr[i] = something you both modified the original array and returned the value "something" which evaluates to true. That's why the original array was modified and the function returned the original array without modification. The map function returns a mapping from the array to the result of the function. Since you both modified the array and returned the same value to which you modified it, you got 2 different arrays with the same values.

Upvotes: 0

Related Questions