【Ruby】inject メソッドの理解

に公開

自己紹介

はじめまして、はると申します。
エンジニアとして働き始めて約1年が経過しました🐣

概要

昨年 Ruby Silver を受験した際に inject メソッドの理解に時間がかかったため、このメソッドについて学習したことを記事にまとめました。

環境

  • Ruby 3.4.1

inject メソッド 基本の使い方

基本の使い方①
inject(初期値){ |result, item| result + item }
# result + item の部分の計算式は自由に変更可
基本の使い方②
inject(symbol)

inject メソッドとは

  • 配列などの要素を1つずつ繰り返してブロック内で要素を注入し処理するメソッドです。
    処理を行い、最終的には1つの値にまとめます

  • たたみこみ演算を行います。1)

このように言葉で表しても、自分はイメージがつかなかったので、図にしました。

array = [1, 2, 3, 4, 5]
p array.inject{ |sum, n| sum + n }
#=> 15

こちらの図のコードでは配列の要素の数(今回だと5個あるので5回)だけ繰り返しを行います
1回目のループでは、n = 1 を代入します。初回なので sum = 0 です。
sum + n0 + 1 = 1 となります。
2回目のループでは、n = 2 を代入します。sum には これまでの処理結果 が入るので、
sum = 1 です。sum + n1 + 2 = 3 となります。
3回目のループでは、n = 3 を代入します。sum には これまでの処理結果 が入るので、
sum = 3 です。sum + n3 + 3 = 6 となります。
4回目のループでは、n = 4 を代入します。sum には これまでの処理結果 が入るので、
sum = 6 です。sum + n6 + 4 = 10 となります。
5回目のループでは、n = 5 を代入します。sum には これまでの処理結果 が入るので、
sum = 10 です。sum + n10 + 5 = 15 となります。

inject メソッドとよく一緒に使われるもの💡

たたみ込み演算を行う二項演算子

  • :+ … 配列の中身を全て 足し合わせる
  • :- … 2つの配列の和集合からの 差分
  • :* … 配列の中身を全て 掛け合わせる
  • :<< … 配列の要素が文字列のとき、文字列を連結する

合わせて使われるメソッド

  • succ&:succ のように書かれている時は、すべての要素に対して、「次」の整数をとる
    p 1.succ
    #=> 2
    
    p -1.succ
    #=> 0
    
  • abs絶対値 を返す(負の符号が外れる)
    p -123.abs
    #=> 123
    
  • abs2 … 絶対値の 2乗 を返す

実行例

学習時に動かして試していたコードを添付します。(Gist)

sample
a = [-1,2,3,4,5]
b = (4..6).to_a

puts "b:#{b}"

puts "---"

p a.inject(:+) + b.inject(:+)

puts "---"

p (a|b).inject(:-).abs
p (a|b).inject(:-).abs + (a&b).inject(:+)

puts "---"

p (a|b).inject(:*)
p b.inject(0){|x,y| x + y ** 3}
p (a|b).inject(:*) + b.inject(0){|x,y| x + y ** 3}

puts "---"

# 複雑な式も分解して計算すれば読み解ける例
p (a||b).map(&:succ) # 0が含まれているためinject(:*)で掛け合わせると0
p (a && b).inject(:*).abs2
p (a||b).map(&:succ).inject(:*) * (a && b).inject(:*).abs2 # 結局ここまでは全て0
p ((a||b).map(&:succ).inject(:*) * (a && b).inject(:*).abs2 + 29 ) # 最後の+29 だけ0じゃない
sample 実行結果
b:[4, 5, 6]
---
28
---
21
30
---
-720
405
-315
---
[0, 3, 4, 5, 6]
14400
0
29

さいごに

最初は苦手意識があったメソッドでしたが、動きを理解すると読めるようになりました。
まだ複雑なメソッドの場合、理解に時間はかかりますが、せっかく資格勉強で覚えたことを無駄にしないよう覚えておきたいです💎

参考記事

引用記事

1)Enumerable#inject (Ruby 3.4 リファレンスマニュアル)

参考記事

Discussion