Hack Your Design!

Ruby の inject メソッドを使いこなす

Rubyのイテレータメソッドinjectの使い方を紹介してみようと思います。

injectの基本的な使い方

Rubyのinjectはこんなふうに使えます。

enum.inject { |memo, item| block }
enum.inject(init) { |memo, item| block }

Sum(合計)を出す

これだけではわかりにくいと思うので合計を出す処理を書いてみましょう。

injectを使わないパターン

まずはinjectを使わないパターン。

sum = 0
(1..10).each {|i| sum += i }
puts sum # => 55

injectを使うパターン

これをinjectで書き直すとこう。

(1..10).inject(0) {|sum, i| sum + i }
# => 55

この場合、sumの初期値をinjectの引数の0で初期化しています。ただinjectのデフォルト引数設定はゼロなので下記のように 省略することができます。

(1..10).inject {|sum, i| sum + i }
# => 55

さらにinjectにはシンボルで演算子をわたしてうまいようにやってくれる。

(1..10).inject(:+)
# => 55

これが一番シンプルでエレガント。

応用編1: 配列内の要素数をハッシュに

Hash.new(0)で初期化してinject.

[:great, :good, :bad, :good, :good, :bad, :awesome, :great].inject(Hash.new(0)) {|hash, key| hash[key] += 1; hash}
# => {:great=>2, :good=>3, :bad=>2, :awesome=>1}

each_with_object を使う

上記の例だとhash[key] += 1; hashとやや冗長な書き方となっていますが、each_with_object使うともう少しシンプルに書けます。

[:great, :good, :bad, :good, :good, :bad, :awesome, :great].each_with_object(Hash.new(0)) {|key, hash| hash[key] += 1}
# => {:great=>2, :good=>3, :bad=>2, :awesome=>1}

応用編2: フィボナッチ数列

inject を利用したフィボナッチ数列ロジック。

(0..10).inject([1, 1]) {|fib, i| fib << fib[i] + fib[i+1] }
# => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233]

応用編3: ループを止める

途中でループを止めて処理を終えたい場合、breakを使えば可能。

(1..5).inject([]) do |ary, number|
  break ary if number == 4
  ary << number
end
# => [1, 2, 3]

番外編: each_with_index

each_with_indexでもinjectは使える。

(1..10).each_with_index.inject(0) { |sum, (value, index)| sum + value }
# => 55

(1..10).each_with_index.inject(0) { |sum, (value, index)| sum + value + index}
# => 100

参考

  • このエントリーをはてなブックマークに追加
comments powered by Disqus