しおブログ言うてますけど

技術ブログ言うてますけど技術以外のことも発信すると思われ。RubyとかRuby on Railsとか生き方とかジャンルにこだわらず自分の好きなように。初心者なのでお手柔らかに。

配列のメソッドまとめ

こんにちは。たかあきです。
Rubyを勉強するときに、最初に買ったチェリー本。いざ学習しようとしたら難しすぎて速攻閉じたのを覚えています。
少したった今、だいぶ慣れ(?)きて、少しずつ理解できるようになってきたのが嬉しくて更にわかるようになりたいと思ってる所存です。
今回はブロックを使う配列のメソッドを参考にまとめていきたいと思う。

map

mapメソッドは各要素に対してブロックを評価した結果を新しい配列にして返す。

例
num = [1, 2, 3, 4 ,5]
new_num = num.map { |n| n * 10 }
new_num #=> [10, 20, 30, 40, 50]

これは各要素の戻り値を10倍にしてnew_numに代入しているため、[10, 20, 30, 40, 50]となる。

さらに省略した書き方ができる。

オブジェクト.map(&:メソッド名)

これは、すべての要素に対して&の後にシンボルで指定したメソッドが繰り返し実行され、結果が配列として返される。

例
country = ["japan", "usa", "china", "brazil"]
big_country = country.map(&:upcase)
big_country #=> ["JAPAN", "USA", "CHINA", "BRAZIL"]

これは変数countryに代入されたjapan、usa、china、brazilという小文字の国名をcountry.map(&:upcase)でcountryのすべての要素を大文字の配列として返している。

select

selectメソッドは戻り値が真の要素を集めた配列を返すメソッド。

age = [23, 1, 33, 72, 35, 5]
even_age = age.select { |n| n.even? }
even_age #=> [72]

これは変数ageに代入された配列[23, 1, 33, 72, 35, 5]から age.select { |n| n.even? }でageの値から偶数だけを配列として返している。
戻り値が真の要素を返すので n.even??が無いと、

NoMethodError (undefined method `even')

のようにエラーが返ってくる。

reject

rejectメソッドはselectメソッドの反対で、戻り値が真の要素を除外した配列を返す。

例
points = [2, 3, 38, 33, 90, 100, 56]
#50以上の数字が真なので 90, 100, 56を除外
below_average = points.reject { |n| n >= 50  }
below_average #=> [2, 3, 38, 33]

少しこんがらがるけど落ち着いて整理すれば処理がわかりやすい。

find

findメソッドはブロックの戻り値が真になった最初の要素を返す

age = [22, 3, 4 ,5 ,66, 42, 55]
old_man = age.find { |n| n > 50  }
# 22, 3, 4 ,5 ,66, 42, 55の中から50より大きい要素は66なので↓
old_man #=> 66

inject

injectはたたみみ込み演算を行うメソッド(最初これが全く意味がわからなかった...)

例
points = [33, 1, 3, 2, ,5, 44, 1, 0, 30]
result = points.inject(0) { |sum, n| sum += n }
result = 119

このコードの解説。
まずinjectの動きとしてブロックの第一引数は初回のみinjectメソッドの引数が入る。上記のコード内でのpoints.inject(0)
第二引数は配列の各要素[33, 1, 3, 2, ,5, 44, 1, 0, 30]が入る。上記のコード内でのn
さらに噛み砕くと、
1回目 : sum = 0。0 + 33 = 33。これが次のsumに入る。
2回目 : sum = 33。33 + 1 = 34。これが次のsumに入る
・ ・ ・ ・ ・ ・
9回目 : sum = sum = 89。89 + 30 = 119。最後の要素に達したので119がinjectメソッドの戻り値になる。
少し複雑な処理だが、噛み砕くとなるほど、、となった。

まとめ

配列はRubyの中でも頻繁に使われるということなので、もっと柔軟な使い方ができるようになりたいと思った。(rejectメソッドはシンプルなのにinjectメソッドはなんでこんなに複雑なのか...もっと頑張るぞ...)