配列を順番に処理するメソッドの色んな書き方

f:id:ryoutaku_jo:20190113142620p:plain

【結論】
・eachやmapなど、配列の要素毎に処理を
 繰り返すメソッドは、省略した書き方がある

・do...endの記述は、中カッコ{}で代用できる

・{|変数| object.method}の代わりに
 (&:method)と記述することも可能

・但し、一行で書く方法は、可読性が悪くなるので、
 複数行に亘る処理を書く場合は、「do...end」推奨


【目次】


【本題】

ワンライナーで書き直せという問題

今日、スクールでこういった問題が出ました。

・問題
以下をワンライナー(一行)で記述してください

array = [1, 2, 3, 4, 5].map do |el| 
  if el.odd?
    el 
  end
end.compact!


処理の流れは、下記の通り。

1:中身が[1, 2, 3, 4, 5]の配列オブジェクトarrayを生成
2:mapで、要素毎に下記で指定する処理を実行。
  要素は変数elと定義して、処理中に取得できる様にする。
3:「if el.odd?」で、取得した要素(el)が奇数(odd?)か判定。
4:奇数(true)なら、elを返す。
奇数で無い(false)なら、何も返さない(nil)
5:3〜4までを全ての要素毎に繰り返す
6:mapにより、5の返り値を集めた配列を作成。
7:end.compact!により、6で作成した配列から
nilの要素を取り除いて、新しい配列を作成。

参考
ref.xaio.jp


後置ifは覚えていたのですが、
繰り返し文をワンライナーで書く方法が思いつきませんでした。

do...endの記述は、中カッコ{}で代用できる

そして答えが、こちらでした(一例)

array = [1, 2, 3, 4, 5].map { |el| el if el.odd? }.compact!
array = (1..5).to_a.delete_if { |el| el.even? }
array = [1, 2, 3, 4, 5].select{ |el| el.odd?}

これを見て初めて気づいたのですが、
中カッコ{}って、do...endの代わりになるんですね。

参考
ref.xaio.jp

{}
中かっこは、ブロックでdo/endの代わりに使われる。

引用元:プログラミング言語Ruby 119ページ

(&:method)と記述することも可能

それと、もう一つこんな書き方もありました。

array = (1..5).to_a.delete_if(&:even?)

これは、{ |el| el.even? }とするところを、
(&:even?)と書き換えています。

この様に、{|変数| object.method}の代わりに
(&:method)と記述することも可能です。

参考
[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか - Qiita


可読性の問題

do..endだと複数行に分かれる処理を、一行にまとめることが
可能になりましたが、
正直見辛いです・・・


スタイルガイドにも、その点について言及されていました。

1行のブロックではdo...endより{...}を使いましょう。
複数行のブロックでは{...}は避けましょう
 (複数行のメソッドチェーンは常に醜いです)。

github.com


使い分ける時は、現場のスタイルガイドに従いましょう。

所感

知っているメソッドでも、知らない書き方があった事が驚きだった。
問題を解く際にも、「違う書き方がある筈」という観点ではなく、
「ワンラインで書ける違うメソッドがある筈」という観点で
検索を行っていたので、自力でたどり着けなかった。

改めて、問題解決には、正しい課題の設定が不可欠だと感じた。


《今日の学習進捗》

JavaScript, jQueryを用いた非同期通信の
実装方法を学習中。今までで一番難しいかも・・・

学習開始からの期間 :37日
今日までの合計時間:360h
今日までに到達すべき目標時間:338h
目標との解離:+22h
「10,000時間」まで、

残り・・・「9640時間!」