Ruby on Rails数组迭代
我是Rails(和ruby)的新手。遍历一个数组以遍历一个变量的标准方式是什么?Ruby on Rails数组迭代
例如在一个月的总支出,第一个数组:
expenses_this_month = expenses.find :all,
:conditions => ['date >= ? and date <= ?',
Date.today.beginning_of_month, Date.today.end_of_month]
我已经是两个途径知道的这样做:
total = 0.0
for expense in expenses_this_month
total += expense.cost
end
return total
或块
total = 0.0
expenses_this_month.each do |expense|
total += expense.cost
end
return total
我m意识到ruby方法中的最后一行将被默认返回,所以必须有更好的书写方式?
您正在寻找的Enumerable#inject
方法:
expenses_this_month.inject(0.0) {|total, expense| total + expense }
这种方法(从Smalltalk中借来的)需要传递给它(在这种情况下,0.0)的值,并设置内部变量了这一点。然后它调用该变量的值(如total
)和每个连续元素(如expense
),并将该变量设置为块返回的任何值(在此情况下为总和与当前元素的总和)。
您可能想要将此计算卸载到数据库,但是,正如kejadlen所示,通过使用#sum
方法。
一旦返回的数据,使用inject
方法:
total = expenses_this_month.inject { |total, expense| total + expense.cost }
但是,你应该重写查询:
total = expenses.sum(:cost, :conditions => ['date >= ? and date <= ?',
Date.today.beginning_of_month, Date.today.end_of_month])
如果你使用Rails,你可以使用内置sum
类方法(假设Expense
是类名)。
expenses_this_month = Expense.sum('cost',
:conditions => ['date >= ? and date <= ?',
Date.today.beginning_of_month,
Date.today.end_of_month])
与Doug建议的一样,inject
方法会很有效。但是,通常最好在数据库中做这样的事情。 ActiveRecord为此提供了一个简单的界面。
total = Expenses.sum :cost, :conditions => {
:date => (Date.today.beginning_of_month..Date.today.end_of_month)
}
请注意,您还可以使用Range对象,而不是SQL插值。
如果由于其他原因而加载所有费用对象,那么注入方法当然没问题。
+ 1显示一个更简洁的方式来传递日期范围。很好的答案! – 2010-01-08 02:13:04
expenses_this_month.map(&:cost).sum
(短,尽管它在内存中的数组不像减少)
expenses_this_month.reduce(BigDecimal.new('0')) { |total, expense| total + expense.cost }
你需要记住传递一个初始值减少(否则会返回空数组零)和处理金钱时,使用BigDecimal而不是常规浮点数。
我一直在金额的数据库中使用十进制类型,但如果我通过(0.0)的方法(减少/注入),它会默认为浮动? 另外,注入和还原有什么特定的区别? – Ryan 2010-01-10 09:19:18
reduce是注入的别名,尽管我认为它是在Ruby 1.8.7中引入的,所以为了向后兼容,您可能想要使用注入。我个人偏好使用map/reduce而不是collect/inject,因为这个术语用于各种编程语言。如果你传递一个float作为初始值来减少Decimal/BigDecimal数字的总和,那么你将执行一个添加float + BigDecimal的操作,这会导致浮点数。 – psyho 2010-01-11 09:48:56
谢谢你的建议。我不使用总和,因为成本是模型中的方法(不是数据库中的列),因为它是根据税率计算的。注入看起来像它会适用于我 – Ryan 2010-01-08 03:38:22