最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - map(), reduce() and filter vs forEach() - Stack Overflow

programmeradmin1浏览0评论

I have just learned about MapReduce, so I wondered if there are any advantages in writing

const initialValue = 0;

if (this.items) {
  return this.items.filter(function (item) {
    return item && item.quantity && item.price;
  }).reduce(function(previousValue, currentValue) {
    return previousValue + currentValue.quantity * currentValue.price ;
  }, initialValue);
} else {
  return initialValue;
}

instead of just

let total = 0;
if (this.items) {
  this.items.forEach(function(item) {
    if (item && item.quantity && item.price) {
      total += item.quantity * item.price;
    }
  });
}
return total;

I have just learned about MapReduce, so I wondered if there are any advantages in writing

const initialValue = 0;

if (this.items) {
  return this.items.filter(function (item) {
    return item && item.quantity && item.price;
  }).reduce(function(previousValue, currentValue) {
    return previousValue + currentValue.quantity * currentValue.price ;
  }, initialValue);
} else {
  return initialValue;
}

instead of just

let total = 0;
if (this.items) {
  this.items.forEach(function(item) {
    if (item && item.quantity && item.price) {
      total += item.quantity * item.price;
    }
  });
}
return total;
Share Improve this question edited Apr 12, 2022 at 22:28 Inigo 15.1k5 gold badges50 silver badges81 bronze badges asked Jan 17, 2016 at 9:07 JamgreenJamgreen 11.1k32 gold badges122 silver badges231 bronze badges 2
  • The first is slower for sure. Also you could use a for-loop to make the second faster – CoderPi Commented Jan 17, 2016 at 9:19
  • If you use MapReduce just to accumulate values (in an iterative way), then there is really no advantage of the first over the second. However don't forget, that the idea behind MapReduce is to be used for parallel putations (distributed systems / clusters). So if the forEach isn't designed resp. implemented to be run in parallel, then it is not suited for distributed environments and the second solution will not work for parallel putations and thus the two solutions are pletely different. – keenthinker Commented Jan 17, 2016 at 10:16
Add a ment  | 

3 Answers 3

Reset to default 7

For future readers, there are a few more idiomatic ways to write the reduction in a functional way. These are generally used because they convey intent a bit more cleanly (and don't add a variable to the scope).

Note: I am assuming this.items has type

({ quantity: number; price: number } | undefined)[] | undefined

but each of the examples is tolerant to even more invalid data than the two in the question.

Filtering and mapping before reducing

Default value at the end

return this.items
    ?.filter(item => item?.quantity && item.price)
    .map(item => item.quantity * item.price)
    .reduce((a, b) => a + b, 0) ?? 0

Default array at the start

return (this.items ?? [])
    .filter(item => item?.quantity && item.price)
    .map(item => item.quantity * item.price)
    .reduce((a, b) => a + b, 0)

Handling the filter within the map

I would not remend these just because the previous two convey intention more clearly.

Default value at the end

return this.items
    ?.map(item => (item?.quantity ?? 0) * (item?.price ?? 0))
    .reduce((a, b) => a + b, 0) ?? 0

Default array at the start

return (this.items ?? [])
    .map(item => (item?.quantity ?? 0) * (item?.price ?? 0))
    .reduce((a, b) => a + b, 0)

Destructuring

Each of the previous examples can be done with destructuring instead. I am including one example.

return (this.items ?? [])
    .filter(item => item) // Ensure item exists; sufficient for the cases we need to worry about
    .map(({ price = 0, quantity = 0 }) => quantity * price)
    .reduce((a, b) => a + b, 0)

Without a map

We can now do the reduction without a map. This can also be done without destructuring, but that is seemingly (to me) inelegant.

return (this.items ?? [])
    .filter(item => item)
    .reduce((sum, { price = 0, quantity = 0 }) => sum + quantity * price, 0)

Of course, you can change the filter condition, which takes us back to roughly the first example in the question:

return (this.items ?? [])
    .filter(item => item?.price && item.quantity)
    .reduce((sum, { price, quantity }) => sum + quantity * price, 0)

Original forEach loop

Some of these changes can be made to the original loop, too:

let total = 0;
items?.forEach((item) => {
  if (item?.quantity && item.price) {
    total += item.quantity * item.price;
  }
});
return total;

I can't see any advantage of the first over the second*. However the second is even faster then the first and looks more clean! The purpose of the first might be to demonstrate the use of built-in array-functions.

However mapreduce is used for a lot of Elements, so you might the speed it up as much as you can. This should be the fastest you can get:

const initialValue = 0;
let total = initialValue;
if (this.items) {
  for (var i = this.items.length; i--;) {
    let item = this.items[i]
    if (item && item.quantity && item.price) {
      total += item.quantity * item.price;
    }
  }
  return total;
} else {
  return initialValue 
}

In addtion you could drop the if inside the loop, if you know that your array is consitant. Both ifs are just there to make sure the array is properly build and the script doesn't run into an Error, that would be usefull for userdata input, but in a closed system you don't need them.


*I noticed that, the second is missing the default value return initialValue

Let's first understand forEach by using the code given below:

        let arr = [2,3,4,5,6];
        
        arr.forEach((value,index,array) => {
            console.log(value,index,array);
        })

In the above code we has used forEach loop in which we can give parameters like value, index, array -- This will return the value then index of that value and full array.

Lets understand maps in maps it will create a new array and return that array

        let a = arr.map((value , index ,array)=>{
            console.log(value , index,array);
            return value + 1;
        })
        console.log(a);
In this you can return the values or change as per you preference like return value*10 or return value + 1;

Lets understand filter in filter it will create a new array and return that array

        let arr2 = [42,3,1,45,5,55];
        
        let a2 = arr2.filter((value)=>{
        return value < 10;
        })
    
    console.log(a2);
In this we can give some condition like return value>10 or return value < 10 ans many more

In reduce method it will return a single value by puting the function

        let arr3 = [1,2,3,5,2,1];
         
        let newarr3 = arr3.reduce((val1,val2) => {
        return val1+val2;
        })
        console.log(newarr3);

In above code firstly val1=1,val2=2 then they sum up as 3 and not val1=3 and val2= is 5 so it will sum up all the elements in an array and return an ans as 14.

IMPORTANT - MAP,FILTER,REDUCE doesn't change your existing array!!

发布评论

评论列表(0)

  1. 暂无评论