3月生募集中!当社人気の転職保証コース
プログラミング学習から転職成功まで導く、当社人気のDMM WEBCAMP(旧WEBCAMP PRO)。
2月生は満員となっております。3月生募集に向け、お早めの申込みをオススメします。
プログラミング未経験でもエンジニア転職を絶対成功させたい
スキルを身に着けて人生を自ら切り開きたい
上記にあてはまる方は、ぜひご検討ください!

プログラムを作っていく中で、数多くのデータを扱うことは少なくありません。そのため、Rubyには配列やハッシュ、それらを使った繰り返し処理が準備されています。

それらの繰り返し処理の中で、「injectメソッド」は比較的難易度が高いメソッドの1つと言えるでしょう。
配列やハッシュを使って繰り返し処理を行うメソッドの1つ「injectメソッド」について、基本的な使い方から応用的な使い方まで、詳しく解説していきます。

Rubyのinjectとは

injectメソッドは、Enumerableクラスのメソッドです。

Enumerableクラスには、eachやmap、selectなどのメソッドが実装されており、injectメソッドもそれらと同じように、配列などの要素数の回数だけ処理を繰り返します。

構文

構文は、引数として初期値を渡す場合と渡さない場合の2種類となっています。

初期値なし

オブジェクト.inject do |ブロック引数1, ブロック引数2|
  処理
end

初期値あり

オブジェクト.inject(初期値) do |ブロック引数1, ブロック引数2|
  処理
end

injectメソッドの動作

injectメソッドの具体的な動きを、以下のプログラムをもとに説明していきます。

inject00-1.rb

arr = [1,2,3,4,5,6,7,8,9]

result = arr.inject do |sum, i|
  sum  + i
end

puts(result)

結果は「45」ですので、それだけを見ると、配列arrの値の合計になっています。しかし、単injectメソッドは、単純に合計を算出しているわけではありません。

あくまでも、繰り返しの処理を行っているのです。ブロック引数の動きを詳細に追っていきましょう。

まず、繰り返しの1回めの動作は、次の通りです。

ブロック引数sumには、配列の最初の要素「1」が代入されます。そして、ブロック引数iには、次の要素の「2」が代入されます。
そして、次がinjectのポイントですが、ブロック内の処理「1 + 1」の結果が、次の繰り返しのブロック引数1(sum)へ代入されるのです。

つまり、繰り返しの処理は(初回以外は)、前回の処理の結果と次の要素を使って処理をすることができるということになります。

その繰り返しを要素数だけ繰り返すことによって、すべての要素の合計値が算出されるわけです。

injectの引数に初期値を設定した場合は、繰り返しの初回でブロック引数1に、初期値、ブロック引数2に配列の1つめの要素の値が格納され、同様の繰り返しが行われます。

inject00-2.rb

arr = [1,2,3,4,5,6,7,8,9]

result = arr.inject(100) do |sum, i|
  sum  + i
end

puts(result)

(結果)

145

Rubyらしいエレガントな記法

injectメソッドには、じつにRubyらしい記載方法も存在しますので、紹介しましょう。

それは、「処理内容がブロック変数の単純な演算処理だった場合、シンボルで演算記号を渡すだけで良い」ということです。

その場合の構文は以下のようになっています。

オブジェクト.inject do |ブロック引数1, ブロック引数2|
  :演算記号
end

演算記号の前に「:」を記載してシンボルの形式にしてやるのがポイントです。

具体的に四則演算をした結果を確認しておきましょう。(商を求めるため、配列の値を浮動小数に変更しています)

arr = [1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0]

puts arr.inject(:+)
puts arr.inject(:-)
puts arr.inject(:*)
puts arr.inject(:/)

(結果)

45.0
-43.0
362880.0
2.7557319223985893e-06

コツコツ独学×スクールで実践。未経験からエンジニアに転職!【WebCamp卒業生インタビュー】

injectの使い方

injectメソッドは、ひとつ前の結果を使って処理を繰り返すメソッドです。そんなメソッドをどう使えば良いのか、あまり思い浮かばないかもしれません

ここからは、実際に使うシーンを想定したいくつかの使いどころを紹介していきましょう。

injectの使いどころ(基本編)

injectメソッドは、うまく使えばとても強力な道具になりますが、初心者には少し難しいと感じさせてしまうことがあります。

その理由のほとんどは「慣れ」の問題ですので、まずは動作を捉えやすい集計処理などで使っていくのが良いでしょう。

点数の集計

ある生徒が3教科のテストを受けた結果が、以下のようにハッシュで与えられているとします。

points = {"math" => 80, "eng" => 65, "koku" => 74}

このデータをもとに、生徒の平均点を算出するプログラムを作ります。

もちろん、injectメソッドを使用しなくても、以下のようにして平均点は算出可能です。

points = {"math" => 80, "eng" => 65, "koku" => 74}

sum = 0
points.values.each { |p| sum += p } # 合計点の計算
ave = sum / points.size             # 平均点の計算

puts(ave)

injectメソッドを利用すれば、以下のように記述することができます。

points = {"math" => 80, "eng" => 65, "koku" => 74}

ave = points.values.inject(:+) / points.size
# ave = points.values.inject {|sum, p| sum += p} / points.size

puts(ave)

eachメソッドの戻り値はオブジェクトが返されますが、injectメソッドの戻り値は集計結果が返されますので、1行で記載することができるわけです。
※コメントアウトしている記載方法でも同じですが、よりRubyらしく、演算記号のシンボルでの記載方法にしています

injectの使いどころ(応用編)

集計でinjectメソッドの動きに慣れてくれば、応用範囲は広がります。

ここでは、集計で必要ですが少し面倒な計数処理(数を数える処理)を紹介します。

重複データの計数

複数回答ありのアンケート結果について、項目ごとの件数を数えます。

データは以下のように、文字列の配列で与えられている状態です。

datas = ["野菜", "くだもの", "肉",
         "デザート", "くだもの", "野菜",
         "魚", "魚", "デザート",
         "くだもの", "くだもの",
         "野菜", "魚", "肉",
         "くだもの", "デザート", "肉"]

このデータの項目ごとの件数を数えていきます。結果はハッシュで返ってくるようにして、分かりやすくしておきましょう。

datas = ["野菜", "くだもの", "肉",
         "デザート", "くだもの", "野菜",
         "魚", "魚", "デザート",
         "くだもの", "くだもの",
         "野菜", "魚", "肉",
         "くだもの", "デザート", "肉"]

total = datas.inject(Hash.new(0)) do |hash, index| # ...(1)
  if hash.has_key?(index)
    hash[index] += 1      # すでに見つけた項目
  else
    hash[index] = 1       # 初めて見つけた項目
  end
  hash                    # 処理の戻り値...(2)
end

puts total

少し複雑ですので、解説します。

(1)の変数totalは、集計結果を格納するためのハッシュです。

また、injectの初期値として「Hash.new(0)」を渡していますが、これは空のハッシュオブジェクトです。結果をこのオブジェクトに格納し、(2)で繰り返し処理の戻り値として戻すわけです。

処理の戻り値は、次の繰り返しでhashに格納されますので、改めて同じハッシュオブジェクトに対して計数処理の結果が格納され、最終的な戻り値として返ってきたhashをtotalが受け取ります。

injectメソッドは、繰り返し処理の中の最後の結果を戻り値として返しますので、その仕組みを使って、ハッシュを作成、受け取っているわけです。

“未経験”でもたった1ヶ月で営業からエンジニアとして転職!『WebCamp』受講者インタビュー

複数人の平均点算出

もう一つ、応用編を紹介しておきましょう。次はもう少し複雑です。

基本編で紹介した生徒の平均点算出について、複数の生徒のデータがあった場合には、どうすれば良いでしょうか?

成績のデータは以下のようにハッシュのハッシュで与えられているものとします。

students = {
            "A" => {"math" => 80, "eng" => 65, "koku" => 74},
            "B" => {"math" => 65, "eng" => 100, "koku" => 81},
            "C" => {"math" => 52, "eng" => 43, "koku" => 100}
           }

生徒A、B、Cそれぞれの平均点を算出し、ハッシュで返す処理を作ってみましょう。

ポイントは以下の3点です。

・平均点の算出を、人数分繰り返すこと
・戻り値は、繰り返しごとの結果をハッシュに格納したもの
・injectメソッドのブロック引数に、結果格納用のハッシュと、studentsの要素を渡すことになる

ポイントを踏まえて作ったのが、以下のプログラムです。

students = {
            "A" => {"math" => 80, "eng" => 65, "koku" => 74},
            "B" => {"math" => 65, "eng" => 100, "koku" => 81},
            "C" => {"math" => 52, "eng" => 43, "koku" => 100}
           }

averages = students.inject(Hash.new(0)) do |aves, (name, points)|
  aves[name] = (points.values.inject(:+)) / points.size
  aves
end

puts(averages)

外側のinjectメソッドへ渡されているのは、前述と同じく空のハッシュオブジェクトですが、この点は前述の応用編で説明済みです。

なにより、ここでのポイントは、ブロック引数でしょう。本来、2つであるはずのブロック引数が、このプログラムでは、3つになっています。正確には、ハッシュオブジェクトと、studentsのキーと値のセットが、ブロック引数として渡されているわけです。
(※この点がクリアになれば、このプリグラムを解析するのはグッと楽になることでしょう)

繰り返し処理の中で、ブロック引数2として渡されたpointsは点数が格納されたハッシュですので、このpointsを使って、基本編と同じやり方で平均点を算出しているのです。

そして、その結果を、ブロック引数2として渡されたnameをキーとして、ブロック引数1のハッシュへ結果を登録しています。

1度で理解するのは、なかなか難しいかもしれませんので、しっくりこなければ何度も復習することをおすすめします。

時間や場所にとらわれず自由に働くために必要なスキルとは?【WebCamp卒業生インタビュー】

問題「最高得点の取得」

次のデータは、あるテストの結果です。

points = {"A"=>55, "B"=>80, "C"=>82, "D"=>81, "E"=>62, "F"=>53, "G"=>81, "H"=>90, "I"=>79}

この中の最高得点を取得してください。

処理結果は、「90」になります。

ヒント1:ハッシュの値だけを取得して、injectメソッドを利用しましょう
ヒント2:繰り返しの戻り値が次の繰り返し処理で利用されることを忘れずに

まとめ

Rubyのinjectメソッドについて、解説しました。

配列やハッシュなどの要素数だけ処理を繰り返すメソッドは多数存在しますが、injectメソッドはその中でもとりわけ応用範囲の広いメソッドと言えます。

しかし、その分動作が複雑で、難しく感じてしまうかもしれません。しかし、何度も使って試行錯誤することで、必ず慣れますので、諦めずに挑戦してください。

もちろん、サイトでの学習ではなく、スクールなどであれば直接質問できますので、理解度はまったく違ってくるでしょう。その点は、本記事のような解説サイトでは絶対に勝てない部分です。

どんな手法にも得意不得意がありますので、何でも活用して、Ruby中級プログラマーを目指していきましょう。

・injectメソッドは、配列やハッシュの要素数だけ処理を繰り返すメソッド
・injectメソッドは、1つ前の繰り返し処理の結果と次の要素の値を使って処理を繰り返す
・injectメソッドの戻り値は、最後の要素の処理結果
・injectメソッドを使えば、総合計や総積数などがシンプルな記述で記載できる

問題の答え

points = {"A"=>55, "B"=>80, "C"=>82, "D"=>81, "E"=>62, "F"=>53, "G"=>81, "H"=>90, "I"=>79}

max = points.values.inject(0) do |max, point|
  if max < point
    max = point
  else
    max
  end
end

puts max

もしくは、3項演算子を使えば、もっとすっきりと書けます。

points = {"A"=>55, "B"=>80, "C"=>82, "D"=>81, "E"=>62, "F"=>53, "G"=>81, "H"=>90, "I"=>79}

max = points.values.inject(0) do |max, point|
  max = max < point ? point : max
end

puts max

DMM WEBCAMP ONLINE/プログラミングコースについて

WEBCAMPでは、「どこでも学べる」オンラインコースを開講しています。

初心者・未経験の方でもわずか1ヶ月でプログラミングの基礎を学び、アプリケーション開発をすることができます。

DMM WEBCAMP ONLINEが選ばれる3つの理由

1.学習の仕方がわからなくても安心!初心者に寄り添った学習カリキュラム

これから学習を始める初心者の方や、独学で挫折してしまった方に向けて、アプリケーション作成をゴールとする一気通貫したカリキュラムを提供しています。2500名を輩出しているWebCampだからこその教室でのリアルな受講生の声を反映し、オンラインコースでも初心者に寄り添った学習体験をご提供いたします。

2.つまずいたらすぐ解決!プロのエンジニアに質問し放題

プログラミング学習で挫折する理由の多くは「つまずいた時に聞ける人がいない」ことです。オンラインコースでは、現役エンジニアやプロ講師に、すぐにチャットでの質問が可能です。つまずきをすぐに解消できるので、挫折せずに学習を継続することができます

3.1ヶ月間で終わらなくても大丈夫!カリキュラムは"卒業後"も"無料"で利用可能

受講したいけど、仕事が急に忙しくなるかもしれないから受講するか迷っている・・・そんな方も多いのではないでしょうか?ご安心ください。カリキュラムは期間終了後も「無料」で使うことができます。また、しっかり学習時間を確保した方も、振り返って学習することでプログラミングスキルがご自身に馴染んできます。

▼まずは無料でWEBデザインのカリキュラムを体験しよう!

【インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!

ブラジルから帰国し技術をつけようとRubyエンジニアを目指してWebCampでRubyを学び、見事Webエンジニアとして転職を果たした田中さんにお話を伺いました。

Rubyの学習がしたい。基礎をしっかりと理解したい

転職のサポートがほしい

と考えている方はぜひお読み下さい。

【WebCamp卒業生インタビュー】1ヶ月でRubyをゼロから学び、Webエンジニアとして転職!

おすすめの記事