16

我有一系列这样的项目:

@items = [
  {price: 12, quantity:1}, 
  {price: 4, quantity:1}, 
  {price: 8, quantity:1}
]

我正在寻找这样的东西:

sumPrice: ->
  @items.sum (item) -> item.price * item.quantity

或者任何尽可能接近这个的东西,这使得每个阅读代码的人都可以非常容易地理解发生了什么。

到目前为止,我想出了:

sumPrice: ->
   (items.map (a) -> a.price * a.quantity).reduce (a, b) -> a + b
  • 包含太多的功能魔法
  • 失去描述性

和:

sumPrice: ->
   sum = 0
   for item in items
     sum += item.price * item.quantity
   sum
  • 新手 JS/Coffee 程序员可以理解
  • 感觉有点傻

我喜欢 CoffeeScript,所以我希望有一个更好的解决方案来解决我想念的类似场景。

4

4 回答 4

14

功能风格还不错。CoffeeScript 允许您像这样美化您的代码:

items
  .map (item) ->
    item.price * item.quantity
  .reduce (x,y) ->
    x+y

这段代码比你的单行代码更容易理解。

如果你不喜欢map你可以用它for来代替。像这样:

(for item in items
  item.price * item.quantity)
  .reduce (x,y)->x+y

或者像这样:

prods = for item in items
  item.price * item.quantity
prods.reduce (x,y)->x+y

或者您可以为数组添加自己的sum()方法:

Array::sum = -> @reduce (x,y)->x+y
(item.price * item.quantity for item in items).sum()
于 2012-12-19T12:19:35.620 回答
13

如果你想表达解决方案,@items.sum (item) -> item.price * item.quantity你可以添加一个sum方法Array

Array::sum = (fn = (x) -> x) ->
  @reduce ((a, b) -> a + fn b), 0

sum = @items.sum (item) -> item.price * item.quantity

请注意,我0作为初始值传递,reduce因此fn为每个数组值调用回调。


如果您不喜欢扩展内置对象,我想如果您在其自己的函数中提取计算单个数组项的总价格的逻辑,我想您可以优雅地将总和表示为单个 reduce:

itemPrice = (item) -> item.price * item.quantity

sum = items.reduce ((total, item) -> total + itemPrice item), 0
于 2012-12-19T15:14:53.850 回答
8

您可以使用解构来稍微简化代码:

sumPrice: ->
    sum = 0
    sum += price * quantity for {price, quantity} in @items
    sum

我认为没有任何方法可以摆脱sum. 虽然 Coffeescript 的for循环语法往往有助于简化原本会使用 的代码map(),但它并没有任何类似的东西可以简化reduce()-type 操作,这就是sumPrice这里所做的。

正如评论中提到的,这个解决方案比调用reduce()or的一个优点sum()是它避免了创建和重复调用函数的开销。

于 2012-12-19T11:14:56.227 回答
2
sum = 0
value = (item) ->
  item.price * item.quantity
sum += value(item) for item in @items
于 2012-12-19T11:50:37.937 回答