map()、reduce() 和 filter 与 forEach()

Jam*_*een 6 javascript performance functional-programming mapreduce

刚刚学习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;
}
Run Code Online (Sandbox Code Playgroud)

而不是仅仅

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

Avi*_*hra 7

对于未来的读者,有一些更惯用的方法可以以函数方式编写归约。通常使用它们是因为它们更清晰地传达意图(并且不向作用域添加变量)。

注意:我假设this.items有类型

({ quantity: number; price: number } | undefined)[] | undefined
Run Code Online (Sandbox Code Playgroud)

但每个示例都比问题中的两个示例能够容忍更多的无效数据。

减少之前的过滤和映射

最后的默认值

({ quantity: number; price: number } | undefined)[] | undefined
Run Code Online (Sandbox Code Playgroud)

开头的默认数组

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

处理地图内的过滤器

我不会仅仅因为前两个更清楚地传达意图而推荐这些。

最后的默认值

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

开头的默认数组

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

解构

前面的每个示例都可以通过解构来完成。我举了一个例子。

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

没有地图

我们现在可以在没有地图的情况下进行缩减。这也可以在不解构的情况下完成,但这似乎(对我来说)不优雅。

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)
Run Code Online (Sandbox Code Playgroud)

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

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

原始forEach循环

其中一些更改也可以对原始循环进行:

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


Cod*_*rPi 0

我看不出第一个相对于第二个有任何优势*。然而,第二个比第一个更快,而且看起来更干净!第一个的目的可能是演示内置数组函数的使用。

然而,mapreduce 用于很多 Elements,因此您可以尽可能地加快速度。这应该是您可以获得的最快的:

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 
}
Run Code Online (Sandbox Code Playgroud)

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


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