开发者

Ruby on rails array iteration

开发者 https://www.devze.com 2022-12-15 23:16 出处:网络
I\'m new to Rails (and ruby). What is the standard way of iterating through an array to total a variable.

I'm new to Rails (and ruby). What is the standard way of iterating through an array to total a variable.

e.g. for the total expenses in a month, first an Array:

expenses_this_month = expenses.find :all,
                                    :conditions => ['date >= ? and date <= ?',
                                      Date.today.beginning_of_month, Date.today.end_of_month]

I already of know of two ways of doing it:

total = 0.0
for expense in expenses_this_开发者_JAVA百科month
  total += expense.cost
end
return total

or with a block

total = 0.0
expenses_this_month.each do |expense|
  total += expense.cost
end
return total

I'm aware that the last line in a ruby method will be returned by default, so there must be a better way of writing this?


The inject method will work great, like Doug suggested. However, it's generally preferable to do things like this in the database when you can. ActiveRecord provides a simple interface for this.

total = Expenses.sum :cost, :conditions => {
  :date => (Date.today.beginning_of_month..Date.today.end_of_month)
}

Note that you can also use a Range object instead of SQL interpolation.

If you're loading all the Expense objects for another reason the inject method is, of course, fine.


You're looking for the Enumerable#inject method:

expenses_this_month.inject(0.0) {|total, expense| total + expense }

This method (borrowed from Smalltalk) takes the value passed to it (0.0 in this case) and sets an internal variable to that. It then calls the block with the value of that variable (as total) and each successive element (as expense), and sets the variable to whatever the block returns (in this case the sum of the total and the current element).

You may want to offload this calculation to the database, though, as kejadlen suggests, by using the #sum method.


expenses_this_month.map(&:cost).sum

(shorter, although it creates an array in memory unlike reduce)

expenses_this_month.reduce(BigDecimal.new('0')) { |total, expense| total + expense.cost }

you need to remember to pass an initial value to reduce (otherwise it will return nil for empty array) and to use BigDecimal instead of regular floats when dealing with money.


Once you have returned the data, use the inject method:

total = expenses_this_month.inject { |total, expense| total + expense.cost }

However, you should just rewrite your query:

total = expenses.sum(:cost, :conditions => ['date >= ? and date <= ?',
                                  Date.today.beginning_of_month, Date.today.end_of_month])


If you're using Rails, you can use the built-in sum class method (assuming Expense is the class name).

expenses_this_month = Expense.sum('cost', 
                                  :conditions => ['date >= ? and date <= ?',
                                                  Date.today.beginning_of_month,
                                                  Date.today.end_of_month])
0

精彩评论

暂无评论...
验证码 换一张
取 消