【问题标题】:Elegantly do a sum of object attributes in CoffeeScript在 CoffeeScript 中优雅地做对象属性的总和
【发布时间】:2012-12-20 07:55:59
【问题描述】:

我有一个这样的数组:

@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,所以我希望有一个更好的解决方案来解决我想念的类似场景。

【问题讨论】:

    标签: coffeescript


    【解决方案1】:

    功能风格还不错。 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()
    

    【讨论】:

    • 功能性的重新缩进看起来不错。我想我一直在保持愚蠢。如果明天之前没有人有更好的方法来写它,我接受你的回答,谢谢!
    • 都是关于最后一个的...[1,2,3,4].sum() ## -> 10
    【解决方案2】:

    如果您想将解决方案表示为@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
    

    【讨论】:

    • 感谢sum的实现!
    • @hakunin 不客气。顺便说一句,我忘了提到 sum 具有标识函数作为默认参数,因此您可以轻松地对数字列表求和 [3, -4, 5].sum() :)
    • 我喜欢“命名函数”的方法,与一大堆回调相比,它使代码更加简洁和自我记录。我可能会更进一步,再添加一个,这样我就可以sumPrices = (t, i) -> t + itemPrice(i); sum = items.reduce(sumPrices, 0)
    • 感谢关于传入初始值的提示!
    【解决方案3】:

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

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

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

    如 cmets 中所述,与调用 reduce()sum() 相比,此解决方案的一个优势是它避免了创建和重复调用函数的开销。

    【讨论】:

    • 除了可读性之外,我认为这个答案优于函数式答案的另一个原因是,它编译为一个简单的 for 循环,它比函数式方法在内存上更快更好。这对你的情况可能无关紧要,但我个人觉得它更具可读性,所以对我来说,这是两全其美的。
    【解决方案4】:
    sum = 0
    value = (item) ->
      item.price * item.quantity
    sum += value(item) for item in @items
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-10
      • 1970-01-01
      • 1970-01-01
      • 2019-06-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-16
      相关资源
      最近更新 更多