map()、reduce() 和 filter() 与 forEach() 的区别

6
我刚学习了MapReduce,所以我想知道是否有编写相关程序的优势。
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;
}

不仅仅是

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

第一个肯定比较慢。此外,您可以使用for循环使第二个更快。 - CoderPi
如果您只是使用MapReduce来累加值(以迭代方式),那么第一种方法与第二种方法相比没有任何优势。但是不要忘记,MapReduce的理念是用于并行计算(分布式系统/集群)。因此,如果forEach没有被设计或实现为并行运行,则它不适用于分布式环境,第二种解决方案将无法用于并行计算,因此这两种解决方案完全不同。 - keenthinker
3个回答

7

针对未来读者,有几种更惯用的方法可以以函数式的方式编写reduction(即归纳操作)。这些方法一般被使用是因为它们更加清晰地传达意图(且不会在作用域中添加变量)。

注意:我假设this.items的类型为

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

但是问题中的这两个示例即使是更多的无效数据它们也能容忍。

在减少之前进行过滤和映射

默认值放在最后

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

开始时的默认数组

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

处理map中的过滤器

我不建议使用这些,因为前面两个选项更清晰地传达了意图。

在末尾设置默认值

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

开始时的默认数组

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

解构

之前的每个例子都可以使用解构来实现,我这里提供一个例子。

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)

没有地图

现在我们可以不使用地图进行简化。 这也可以在不使用解构的情况下完成,但这似乎(对我而言)是不优雅的。

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

当然,您可以更改筛选条件,这将使我们回到问题的大致第一个示例:

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

原始的forEach循环

原始的循环也可以进行一些改变:

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

0

我看不出第一种方法比第二种方法优势在哪里。但是第二种方法比第一种方法更快,而且看起来更加简洁!第一种方法的目的可能是为了展示内置数组函数的使用。

然而,mapreduce 用于许多元素,因此您可能需要尽可能提高其速度。这应该是您能够获得的最快速度:

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 
}

此外,如果您知道您的数组是一致的,您可以在循环内部省略if。这两个if只是为了确保数组被正确构建,并且脚本不会遇到错误。对于用户数据输入来说,这非常有用,但在封闭系统中,您不需要它们。

*我注意到第二个缺少默认值 return initialValue


-1
首先,让我们通过下面给出的代码来了解forEach的用法:
        let arr = [2,3,4,5,6];
        
        arr.forEach((value,index,array) => {
            console.log(value,index,array);
        })

在上面的代码中,我们使用了forEach循环,可以给出参数如value、index、array -- 这将返回该值的索引和完整数组。
让我们来了解一下maps,在maps中它会创建一个新的数组并返回该数组。
        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;

让我们理解一下在filter中的筛选,它将创建一个新数组并返回该数组。
        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

在reduce方法中,它通过计算函数来返回一个单一的值。
        let arr3 = [1,2,3,5,2,1];
         
        let newarr3 = arr3.reduce((val1,val2) => {
        return val1+val2;
        })
        console.log(newarr3);

在上面的代码中,首先val1=1,val2=2,然后它们相加得到3,而不是val1=3和val2=5,所以它将对数组中的所有元素求和,并返回结果为14。
重要提示:MAP、FILTER和REDUCE不会改变您现有的数组!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接