Итерация массива Ruby on rails - PullRequest
       12

Итерация массива Ruby on rails

1 голос
/ 08 января 2010

Я новичок в Rails (и ruby). Каков стандартный способ перебора массива для суммирования переменной.

например. на общую сумму расходов за месяц, сначала массив:

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

Я знаю, что последняя строка в методе ruby ​​будет возвращена по умолчанию, поэтому должен быть лучший способ написать это?

Ответы [ 5 ]

4 голосов
/ 08 января 2010

Метод inject будет отлично работать, как предложил Даг. Однако, как правило, лучше делать такие вещи в базе данных, когда это возможно. ActiveRecord предоставляет простой интерфейс для этого.

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

Обратите внимание, что вы также можете использовать объект Range вместо SQL-интерполяции.

Если вы загружаете все объекты Expense по другой причине, метод inject, конечно, подойдет.

3 голосов
/ 08 января 2010
expenses_this_month.map(&:cost).sum

(короче, хотя он создает массив в памяти в отличие от сокращения)

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

вам нужно помнить, что нужно передать начальное значение для уменьшения (в противном случае он вернет nil для пустого массива) и использовать BigDecimal вместо обычных чисел с плавающей точкой при работе с деньгами.

3 голосов
/ 08 января 2010

Вы ищете метод Enumerable#inject:

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

Этот метод (заимствованный из Smalltalk) принимает переданное ему значение (в данном случае 0.0) и устанавливает для него внутреннюю переменную. Затем он вызывает блок со значением этой переменной (как total) и каждого последующего элемента (как expense), и устанавливает переменную равной тому, что возвращает блок (в этом случае сумма итогового и текущего элементов) ).

Возможно, вы захотите перенести этот расчет в базу данных, хотя, как предполагает Кеджадлен, с помощью метода #sum.

2 голосов
/ 08 января 2010

После того, как вы вернули данные, используйте метод 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])
1 голос
/ 08 января 2010

Если вы используете Rails, вы можете использовать встроенный метод класса sum (при условии, что Expense - это имя класса).

expenses_this_month = Expense.sum('cost', 
                                  :conditions => ['date >= ? and date <= ?',
                                                  Date.today.beginning_of_month,
                                                  Date.today.end_of_month])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...