この記事で扱うRuby配列メソッド
1.selectメソッド
2.rejectメソッド
3.keep_ifメソッド
4.delete_ifメソッド
5.findメソッド
6.mapメソッド
Rubyバージョン: 2.5.1 で動作確認
書いたきっかけ
今まで配列メソッドといえばeach メソッド
くらいしか使ったことありませんでした。(筆者はプログラミングを本格的に学習し始めて2ヶ月程度の初心者です。)
Rails で個人アプリを開発中、「DBテーブルから取得した配列データをうまい具合に加工して必要な要素だけ表示したいけど、うまくできない」っていうことが多々。
解決のために色々と調べる中で「こんなに便利なメソッドがあったのか!」と非常に勉強になったので、 知識の定着兼、備忘録として書こうと思います。
どなたかの参考になれば幸いです。
※eachメソッド
は使いこなせている、というくらいのレベル感の方を対象として書いています。
参考にしたもの
伊藤淳一さんの 「プロを目指す人のためのRuby入門」
伊藤さんのQiita記事、書籍等非常にわかりやすく、いつもお世話になっています。
今回動作確認用サンプルとして用意した配列
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
以下で一つ一つメソッドの動作を確認しつつ解説していきます。
1.selectメソッド
selectメソッド
は配列の各要素に対してブロック内で指定した処理を行う。その戻り値がtrue
の要素だけを集めた配列を返す。
実際に動作を確認
# scoreが70以上のuserだけにしたい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
# selectを用いてscoreが70以上のuserのみを集める
goukaku_users = users.select { |user| user[:score] >= 70 }
# 新しく作成した変数の中身を確認
p goukaku_users
# =>[{:name=>"松田", :score=>80}, {:name=>"小池", :score=>90}, {:name=>"藤沢", :score=>85}]
# score70以上のuserだけの配列を作成できた!
※この記事ではブロックの中では簡単な処理しか行わないので
do...end
を { }
を用いる記法1行で書いています。
蛇足ですが、変数名などわかりずらかったらすみません。
2.rejectメソッド
rejectメソッド
はselectメソッド
とは反対で、ブロック内での処理の戻り値がfalse
の要素だけを集めた配列返すメソッド。
実際に動作を確認
# scoreが70以下のuserだけにしたい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
# rejectメソッドでscoreが70以下のuserのみを集める
fugoukaku_users = users.reject { |user| user[:score] > 70 }
# 新しく作成した変数の中身を確認
p fugoukaku_users
# => [{:name=>"大塚", :score=>60}, {:name=>"井上", :score=>40}, {:name=>"松本", :score=>50}]
# score70以下のuserだけの配列を作成できた!
3.keep_ifメソッド
keep_ifメソッド
も配列の各要素を順番に取り出してブロック内で指定した処理を行う。その結果、戻り値がtrue
であればブロックに渡した要素を配列に残し、戻り値がfalse
であれば配列から削除する。
実際に動作を確認
# scoreが70以上のuserだけにしたい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
# keep_ifメソッドでscoreが70以上のuserのみに加工する
# scoreが70より小さいusersの要素は削除
users.keep_if { |user| user[:score] >= 70 }
# keep_ifメソッド後
p users
# => [{:name=>"松田", :score=>80}, {:name=>"小池", :score=>90}, {:name=>"藤沢", :score=>85}]
# 元の配列usersをscore70以上のuserだけの配列にできた!
4.delete_ifメソッド
delete_ifメソッド
も配列の各要素を順番に取り出してブロック内で指定した処理を行う。その結果、戻り値がtrue
であればブロックに渡した要素を元の配列から削除する。戻り値がfalse
であれば配列に残す。
実際に動作を確認
# scoreが70以下のuserだけにしたい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
# delete_ifメソッドでscoreが70以下のuserのみに加工する
# scoreが70より大きいusersの要素は削除
users.delete_if { |user| user[:score] > 70 }
# delete_ifメソッド後
p users
# => [{:name=>"大塚", :score=>60}, {:name=>"井上", :score=>40}, {:name=>"松本", :score=>50}]
# 元の配列usersをscore70以下のuserだけの配列にできた!
keep_if
、delete_ifメソッド
は 1,2で説明したselectメソッド
、rejectメソッド
と同じ!?
と思ったのですが、比較すると
select / reject
元の配列はそのままに、条件に当てはまった要素を集めて全く新しい配列を返す。そのため再利用する際は変数へ代入する。
delete_if / keep_if
元の配列から条件に当てはまった要素を削除する。つまり元の配列の形自体を変えている。そのため、元の変数名で再利用が可能。
似ているのですがこんな違いがあるようです。
5.findメソッド
findメソッド
はブロックで指定した処理の戻り値がtrue
になる最初の要素を返す。
実際に動作を確認
# 配列usersのscoreが70以上の最初のuserを取得したい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
# findメソッドでscoreが70以上の最初のuserを取得
goukaku_user = users.find { |user| user[:score] >= 70 }
# 新しく作成した変数の中身を確認
p goukaku_user
# => {:name=>"松田", :score=>80}
# 配列のscore70以上の最初のuserを取得できた!
念のため、ブロック内 score の条件を 70 → 85 に変えてみて再度検証
# 配列usersのscoreが85以上の最初のuserを取得したい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
# findメソッドでscoreが85以上の最初のuserを取得
goukaku_user = users.find { |user| user[:score] >= 85 }
# 新しく作成した変数の中身を確認
p goukaku_user
# => {:name=>"小池", :score=>90}
# 配列のscore85以上の最初のuserを取得できた!
6.mapメソッド
mapメソッド
は各要素に対してブロック内で指定した処理の結果、戻り値を新しい配列にして返す。
実際に動作を確認
# 配列usersのnameに「さん」を付けたい!
users = [
{name: '松田', score: 80},
{name: '大塚', score: 60},
{name: '小池', score: 90},
{name: '井上', score: 40},
{name: '松本', score: 50},
{name: '藤沢', score: 85}
]
san_users = users.map { |user| user[:name] + 'さん' }
# 新しく作成した変数の中身を確認
p san_users
# => ["松田さん", "大塚さん", "小池さん", "井上さん", "松本さん", "藤沢さん"]
あれ? ちょっと期待した動作と違った。
mapメソッド
は今まで説明してきた配列メソッドとは少し異なる挙動をするよう。
具体的には、
元の配列の要素を評価して、要素を変形させて値を返す訳ではなく、処理結果の返り値をそのまま一つずつ配列に格納し、新しく作成した配列を返している。
javaScriptの mapメソッドを知っている方なら、理解しやすいかもしれないです。
# なので元の形を維持しつつ、ハッシュ形式で返したい場合は次のように書く
san_users = users.map { |user| {name: user[:name]+'さん', score: user[:score]} }
p san_users
# => [{:name=>"松田さん", :score=>80}, {:name=>"大塚さん", :score=>60}, {:name=>"小池さん", :score=>90}, {:name=>"井上さん", :score=>40}, {:name=>"松本さん", :score=>50}, {:name=>"藤沢さん", :score=>85}]
# nameに「さん」をつけた配列を作成できた!
最後に
記事を読んでいただきありがとうございます。
Rails で開発をしていて、メソッドを知らないと知っているではできることの範囲やコードリファクタリングなどに大きく影響してくることを痛感。改めて基礎の大切さを感じているところです。
内容に誤りなどあれば、気軽にご指摘、ご意見いただけると嬉しいです!