user5047085
user5047085

Reputation:

How to map + filter in single loop

I have asked this question on SO before but I cannot find the question/answers!

Basically I want to create this:

Array.prototype.filterAndMap = function(){};

where I can use it like so:

[1,2,3,4,5].filterAndMap(function(){
     if(i % 2 === 0){
        return i*2;
     }
});

the above would return:

  [4,8]

I think the best way to implement this is using Array.prototype.reduce...but I am not sure.

What I am trying to avoid, is iterating through the list twice:

   [1,2,3,4,5].filter(function(){
         return i % 2 === 0;
    })
    .map(function(i){
         return i * 2;
    });

Upvotes: 1

Views: 1692

Answers (5)

kind user
kind user

Reputation: 41893

It's likely impossible to combine these two methods (.map and .filter) since .filter doesn't do any logic on elements and .map always return every element from given array. Hovewer you could try .reduce approach, to return only that element, which fulfills given condition.

const arr = [1,2,3,4,5];

const r = arr.reduce((s, a) => (a % 2 ? null : s.push(a * 2), s), []);

console.log(r);

Upvotes: 1

ncardeli
ncardeli

Reputation: 3492

Your question has been answered in specific ways, according to your sample code.

If what you are trying to accomplish is a generic function to filter and map (although it is not a map, it is a reduce), this is what you are looking for:

var filterAndReduce = function(arr, filterFn, fn) {
  return arr.reduce(function(r, a) {
        return r.concat(filterFn(a) ? [] : fn(a));
  }, []);
};

You would use it this way:

filterAndReduce([1,2,3,4,5], function(i) {
     return i % 2;
},
function(i) {
    return i * 2
});

Upvotes: 0

CRice
CRice

Reputation: 32146

As you say, reduce is probably the way to go:

const myArray = [1, 2, 3, 4, 5];

function mapAndFilter(array, filterFunc, mapFunc) {
    return array.reduce((p, c) => {
        if (filterFunc(c)) p.push(mapFunc(c));
        return p;
    }, []);
}

const mapFilteredArray = mapAndFilter(myArray, x => x % 2 === 0, x => x*2);
console.log(mapFilteredArray);

Adapt that function to go on the array prototype as you please.

Upvotes: 0

ajm
ajm

Reputation: 20105

reduce would certainly do the trick:

[1,2,3,4,5].reduce((arr, cur) => { 
   if(cur % 2 == 0){
      arr.push(cur * 2); 
   }
   return arr;
}, []);   // => [2, 4]

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386560

You could iterate the array and concat the value if valid or an empty array if not.

var array = [1, 2, 3, 4, 5],
    result = array.reduce(function(r, a) {
        return r.concat(a % 2 ? [] : 2 * a);
    }, []);
    
console.log(result);

ES6

var array = [1, 2, 3, 4, 5],
    result = array.reduce((r, a) => r.concat(a % 2 ? [] : 2 * a), []);
    
console.log(result);

Upvotes: 2

Related Questions