2012-12-19 48 views
14

我有一個項目,像這樣的數組:優雅做對象的總和屬性中的CoffeeScript

@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 /咖啡程序員
  • 理解感覺有點笨

我愛CoffeeScript的,所以我希望有一個更好的解決方案,我錯過這個&類似的場景。

回答

11

如果你想表達的解決方案@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回調函數將針對每個數組值調用。


如果你不喜歡延長內置的對象,我想你可以表達作爲一個單一的降低優雅如果你提取計算總價格在其自身的功能單一陣列中物品的邏輯總和:

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

sum = items.reduce ((total, item) -> total + itemPrice item), 0 
+0

謝謝你的總和! – hakunin

+1

@hakunin不客氣。順便說一句,我忘了提及'sum'具有身份函數作爲默認參數,所以你可以簡單地總結一個數字列表'[3,-4,5] .sum()':) – epidemian

+0

我喜歡「命名函數「方法,使得代碼比一大堆回調更加清潔和自我記錄。我可能會更進一步,並添加另一個,這樣我可以'sumPrices =(t,i) - > t + itemPrice(i); sum = items.reduce(sumPrices,0)'。 –

7

你可以用解構略有簡化代碼:

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

我不認爲有任何的方式來擺脫sum明確的初始化。儘管Coffeescript的for循環語法傾向於幫助簡化本來使用map()的代碼,但它實際上並沒有任何類似的內容可以簡化reduce()類型的操作,這就是sumPrice在此處所做的操作。

正如評論中所述,該解決方案對reduce()sum()的調用具有的一個優點是它避免了創建和重複調用函數的開銷。

+3

除了可讀性,另一個原因是我相信這個答案是superiour的那些功能是,這個編譯成一個簡單的for循環是對內存比功能的方法更快,更好。這可能與你的情況無關,但我個人覺得它更具可讀性,對我來說,這是兩全其美的。 –

2
sum = 0 
value = (item) -> 
    item.price * item.quantity 
sum += value(item) for item in @items 
12

功能風格並不那麼糟糕。 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() 
+0

功能重新壓縮看起來不錯。我認爲我保持愚蠢的一個雖然。如果沒有人用更好的方式寫到明天,我接受你的答案,謝謝! – hakunin

+0

這是關於最後一個...'[1,2,3,4] .sum()## - > 10' –