Программирование на языке Ruby.

8.3.1. Метод inject.

Метод inject пришел в Ruby из языка Smalltalk (впервые он появился в версии Ruby 1.8). Его поведение интересно, хотя с первого раза понять его нелегко.

Он отражает тот факт, что мы часто хотим обойти список и по ходу «аккумулировать» некоторый результат. Конечно, самый естественный пример — суммирование чисел в списке. Но и для других операций обычно есть некий «аккумулятор» (которому присваивается начальное значение) и применяемая функция (в Ruby она представлена блоком).

В качестве тривиального примера рассмотрим массив чисел, которые нужно просуммировать:

Nums = [3,5,7,9,11,13].

Sum = nums.inject(0) {|x,n| x+n }.

Обратите внимание, что начальное значение аккумулятора равно 0 («нейтральный элемент» для операции сложения). Затем блок получает текущее значение аккумулятора и значение текущего элемента списка. Действие блока заключается в прибавлении нового значения к текущей сумме.

Ясно, что этот код эквивалентен следующему:

Sum = 0.

Nums.each {|n| sum += n }.

В данном случае уровень абстракции лишь немногим выше. Если идея метода inject не укладывается у вас в голове, не пользуйтесь им. Но если удалось преодолеть первоначальное непонимание, то вы сможете найти ему новые элегантные применения.

Начальное значение аккумулятора задавать необязательно. Если оно опущено, то в качестве такового используется значение первого элемента, который при последующих итерациях пропускается,

Sum = nums.inject {|x,n| x+n }.

# To же самое, что:

Sum = nums[0].

Nums[1..-1].each {|n| sum + = n }.

Другой похожий пример — вычисление произведения чисел. В данном случае аккумулятору следует присвоить начальное значение 1 (нейтральный элемент для операции умножения).

Prod = nums.inject(1) {|x,n| x*n }.

# или.

Prod = nums.inject {|x,n| x*n }.

В следующем немного более сложном примере мы находим самое длинное слово в списке:

Words = %w[ alpha beta gamma delta epsilon eta theta ].

Longest_word = words.inject do |best,w|

 w.length > best.length ? w : best.

End.

# Возвращается значение "epsilon".