はじめに
どうも、もきおです。Rubyのループ処理はfor,each,mapなど色々と選択肢がありますよね。今回はループ処理をより簡潔に書く方法をメモとして残しておきたいと思います。
最後に実務でループ処理をどうリファクタリングしていったかを記載しておくので最後までご覧いただけますと幸いです。
データ作成
まずはデータを作成していきます。今回はnameカラムを持ったuserを作成し、userをループ処理してnameを配列に格納してname一覧を作成するという処理をしていきます。
class User
attr_accessor :name
end
user1 = User.new
user1.name = "鈴木"
user2 = User.new
user1.name = "佐藤"
user3 = User.new
user1.name = "小林"
users = [user1, user2, user3]
eachでループ処理して配列作成
まずはeach文。each文でループ処理して新たな配列に格納するには事前に空配列を定義しておく必要があります。
names = []
users.each do |user|
names << user.name
end
p names
#=> ["鈴木", "佐藤", "小林"]
mapでループ処理して配列作成
今回みたいにループで回し、各々を処理した結果を新しい配列に格納したい場合はeachよりもmapの方が簡単に記述する事ができます。mapの場合は事前に空配列を定義していなくてもそのまま配列に格納していく事ができます。
names = users.map do |user|
user.name
end
#=> ["鈴木", "佐藤", "小林"]
ブロックを使ってより簡潔にループ処理を書く
続いて今回みたいにループ中の処理が1行のみという簡単な処理の場合 (1行でなくても可能です)、ブロックを使用することによってより簡潔に記述する事ができます。
names = users.map { |user| user.name }
#=> ["鈴木", "佐藤", "小林"]
前項の処理がこのように1行で記述する事ができてしまいます。これは実務コードでも良く見かけますし使います。
&:を使用して更に簡潔にループ処理を書く
最後にブロックを使用するよりも更に簡潔に記述できる方法があります。アンパサンド(&)とメソッド名をシンボルで(:)囲みます。
names = users.map(&:name)
#=> ["鈴木", "佐藤", "小林"]
(&:)が何をやっているのかというのは以下の記事が参考になりました。
実務でループ処理をどう簡潔に書くか
最後に実務でループ処理をどうリファクタリングしていったかを記載して終わろうと思います。今回はaccountsに複数のアカウントが格納されており、それぞれ売上(sale)カラムを所持しているという設定。アカウントの総売上を求めたいとします。
まずはeachでループ処理して算出する方法
sale_total = []
accounts.each do |account|
sale_total += account.sale
end
次にpluckメソッドを使用し売上一覧を配列にし、それをsumメソッドで合計する方法
sale_total = accounts.pluck(:sale).sum
# [1000, 2000, 3000, 4000].sum
p sale_total
# => 10000
pluckメソッドはカラムの値一覧例:[1000, 2000, 3000, 4000]
を配列として取り出してくれるというメソッドです。
何度も値一覧を使用したい場合、配列として取り出しておけば、都度クエリを発行しなくて済むので、pluckメソッドは実務でめちゃくちゃ使います。実務でRubyを使用するなら覚えておいて損はないかと思います。
最後に&:
を使用する方法
sale_total = accounts.sum(&:sale)
p sale_total
# => 10000
こんな感じで最終的にここまで簡潔に記載する事ができました。
あとがき
いかがだったでしょうか?実務コードを読んでいて(&:)の記載を見た時何これ状態でした。こうやって地道に調べていってコードの理解を深めていきたいと思います。
最後までご覧いただき本当にありがとうございました!!
Twitterでも日頃の業務で思ったことを呟いていくのでご覧いただけると幸いです。
@mokio_50