Ruby学習メモ ブロックを使う配列のメソッド
<map/collect>
mapメソッド(エイリアスメソッドはcollect)は各要素に対してブロックを評価した結果を新しい配列にして返す。
例えば、次のように配列の各要素を10倍した新しい配列を作るコードがあったとする。
numbers = [1, 2, 3, 4, 5]
new_numbers = []
numbers.each { |n| new_numbers << n * 10 }
new_numbers #=> [10, 20, 30, 40, 50]
mapメソッドを使うとブロックの戻り値が配列の要素となる新しい配列が作成されるため、mapメソッドの戻り値をそのまま新しい変数に入れることができる。
numbers = [1, 2, 3, 4, 5]
# ブロックの戻り値が新しい配列の各要素になる
new_numbers = numbers.map { |n| n * 10 }
new_numbers #=> [10, 20, 30, 40, 50]
空の配列を用意して、他の配列をループ処理した結果を空の配列に詰め込んでいくような処理の大半は、mapメソッドに置き換えることができる。
<select/find_all/reject>
selectメソッド(エイリアスメソッドはfind_all)は各要素に対してブロックを評価し、その戻り値が真の要素を集めた配列を返すメソッド。
偶数の数値だけを集めた配列を新たに作ることができる。
numbers = [1, 2, 3, 4, 5, 6]
new_numbers = numbers.select { |n| n.even? }
new.numbers #=> [2, 4, 6]
rejectメソッドはselectメソッドの反対で、ブロックの戻り値が真になった要素を除外した配列を返す。
言い換えると、ブロックの戻り値が偽である要素を集めるメソッド。
numbers = [1, 2, 3, 4, 5, 6]
non_multiples_of_three = numbers.reject { |n| n % 3 == 0 }
non_multiples_of_three #=> [1, 2, 4, 5]
<find/detect>
findメソッド(エイリアスメソッドはdetect)はブロックの戻り値が真になった最初の要素を返す。
numbers = [1, 2, 3, 4, 5, 6]
even_number = numbers.find { |n| n.even? }
even_number #=> 2
<inject/reduce>
injectメソッド(エイリアスメソッドはreduce)はたたみ込み演算を行うメソッド。
次のコードはeachメソッドを使って1から4までの値を変数sumに加算していくコード。
numbers = [1, 2, 3, 4]
sum = 0
numbers.each { |n| sum+= n }
sum #=> 10
上のコードはinjectメソッドを使用すると次のように書ける。
numbers = [1, 2, 3, 4]
sum = numbers.inject(0) { |result, n| result + n }
sum #=> 10
ブロックの第1引数(result)は初回のみinjectメソッドの引数(0)が入る。2回目以降は前回のブロックの戻り値が入る。
ブロックの戻り値は次の回に引き継がれ、ブロックの第1引数(result)に入る。繰り返し処理が最後まで終わると、ブロックの戻り値がinjectメソッドの戻り値となる。
<&とシンボルを使ってもっと簡潔に書く>
ブロックを使うメソッドは条件によってはかなり簡潔に書くことがきできる。
# このコードは
[‘ruby’, ‘java’, ‘perl’].map { |s| s.upcase } #=> [“RUBY”, “JAVA”, “PERL”]
# こう書き換えられる
[‘ruby’, ‘java’, ‘perl’].map(&:upcase) #=> [“RUBY”, “JAVA”, “PERL”]
# このコードは
[1, 2, 3, 4, 5, 6].select { |n| n.odd? } #=> [1, 3, 5]
# こう書き換えられる
[1, 2, 3, 4, 5, 6].select(&:odd?) #=> [1, 3, 5]
mapメソッドやselectメソッドにブロックを渡す代わりに、&:メソッド名という引数を渡している。
この書き方は次に条件が揃った時に使うことができる。
①ブロック引数が1個だけである。
②ブロックの中で呼び出すメソッドに引数がない。
③ブロックの中では、ブロック引数に対してメソッドを1回呼び出す以外の処理がない。