在您的文章中定義cost
的關鍵明顯是inject
方法。 inject
方法也可以調用爲reduce
,這對於許多英語用戶來說是一個更明智的名稱,因爲它需要一個列表並將其減少爲單個值。 (只是在功能編程的文獻中進一步混淆了事物,這個函數幾乎總是被稱爲「摺疊」)。
有很多例子;考慮找到整數列表的總和:
[1,2,3,4,5].inject(0) {|sum, num| return sum + num} #=> 15
那麼這裏發生了什麼?塊的第一個參數是運行結果 - 在這種情況下的部分總和。它以任何你通過的參數inject
(在上面的例子中爲0)開始。
該塊在列表中每個項目調用一次,當前項目成爲第二個參數。塊返回的值成爲塊的下一次迭代的運行值(第一個參數)。
因此,如果我們擴大上述注入更加明確必要的代碼,我們得到這樣的:
def block(sum, num)
return sum + num
end
result = 0
for i in [1,2,3,4,5]
result = block(result, i)
end
有了這些知識,讓我們來解決cost
:
def cost(*orders)
orders.inject(0) do |total_cost, order|
total_cost + order.keys.inject(0) {|cost, key| cost + @menu[key]*order[key] }
end
end
首先,它採取您可以在Ruby中取消return
的優勢;塊中最後一個表達式的值是該塊的返回值。
這兩個inject
調用看起來很像我上面的例子 - 他們只是簡單的求和循環。 外部inject
構建了所有單個訂單的總額,但由於這些訂單是地圖而不是數字,因此在將每個訂單添加到一起之前,必須做更多的工作才能獲得每個訂單的成本。那「更多的工作」是呼叫的內在的inject
。
order.keys.inject(0) {|cost, key| cost + @menu[key]*order[key] }
用我上面的擴展,你可以看到這是如何工作 - 它只是增加了每個值的順序(項目數量)次相乘的結果,該項目(密鑰)的價格根據菜單。順便說一句,您可以避免必須通過減少鍵/值對而不是僅查找值來查找塊內部的順序圖中的鍵。您還可以利用的事實,如果你沒有在初始值傳遞給inject
/reduce
,它默認爲零:
orders.inject { |grand_total, order|
grand_total + order.inject { |subtotal, line_item|
item, quantity = line_item
subtotal + quantity * @menu[item]
}
}
查找施帕爾特運營商,並期待在使用注射功能的一些示例。 – hirolau
@hirolau,'s/spalt/splat /'。 –
如果您對任何答案感到滿意,您應該檢查對您最有幫助的答案。 –