简体   繁体   English

Ruby on Rails数组迭代

[英]Ruby on rails array iteration

I'm new to Rails (and ruby). 我是Rails(和ruby)的新手。 What is the standard way of iterating through an array to total a variable. 遍历数组以累加变量的标准方法是什么?

eg 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_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? 我知道ruby方法的最后一行将默认返回,因此必须有更好的编写方法吗?

The inject method will work great, like Doug suggested. inject方法会很好用,就像Doug建议的那样。 However, it's generally preferable to do things like this in the database when you can. 但是,通常最好在可能的情况下在数据库中执行类似的操作。 ActiveRecord provides a simple interface for this. ActiveRecord为此提供了一个简单的界面。

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. 请注意,您还可以使用Range对象代替SQL插值。

If you're loading all the Expense objects for another reason the inject method is, of course, fine. 如果由于其他原因要加载所有Expense对象,则注入方法当然可以。

You're looking for the Enumerable#inject method: 您正在寻找Enumerable#inject方法:

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. 此方法(从Smalltalk借用)采用传递给它的值(在这种情况下为0.0),并为此设置内部变量。 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). 然后,它将使用该变量的值(作为total )和每个后续元素(作为expense )的值调用该块,并将变量设置为该块返回的值(在这种情况下,total和当前元素之和)。

You may want to offload this calculation to the database, though, as kejadlen suggests, by using the #sum method. 但是,正如kejadlen所建议的那样,您可能希望通过使用#sum方法将此计算卸载到数据库中。

expenses_this_month.map(&:cost).sum

(shorter, although it creates an array in memory unlike reduce) (较短,尽管它与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. 您需要记住传递一个初始值来减少(否则它将为空数组返回nil),并在处理货币时使用BigDecimal而不是常规浮点数。

Once you have returned the data, use the inject method: 返回数据后,请使用inject方法:

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). 如果您使用的是Rails,则可以使用内置的sum类方法(假设Expense是类名)。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM