Ruby学習 「プロを目指す人のためのRuby入門」 4章

はじめに

プロを目指す人のためのRuby入門Rubyを学習しています。
大事そうな部分や理解が難しかった部分、忘れそうなことについて学習メモを書きます。
今回は第4章「配列や繰り返し処理について理解する」について書いていきます。

記事中のプログラムはirbで動作を確認しました。

配列

  • 異なるデータ型を格納できる
data = [10, 'dog', 2, 'cat']
=> [10, "dog", 2, "cat"]
  • 存在しない要素を取得しようとしてもエラーは発生せず、nilが戻る
data = [10, 'dog', 2, 'cat']
=> [10, "dog", 2, "cat"]

data[10]
=> nil

要素の変更、追加、削除

  • 元の配列サイズより大きい添え字を指定して値を代入すると、間の値はnilが設定される
array = [10, 20, 30]
=> [10, 20, 30]

array[5] = 60
=> 60

array
=> [10, 20, 30, nil, nil, 60]
  • 配列 << 10で末尾に要素を追加できる
  • 配列の特定の位置の要素を削除する場合はdelete_atメソッドを使用する
array = [10, 20, 30]
=> [10, 20, 30]
array.delete_at(1)
=> 20
array
=> [10, 30]
  • 配列の要素を変数に多重代入できる

ブロック

  • 配列の値を順番に処理する時はeachメソッドを使う(for文もあるがほぼ使わない)
array = [10, 20, 30]
=> [10, 20, 30]
sum = 0
=> 0
array.each do |number|
  sum += number
end
=> [10, 20, 30]
sum
=> 60
  • 配列の特定の条件に一致する要素を削除する時はdelete_ifメソッドを使う
  • ブロック引数は省略可能
  • ブロック内で宣言した変数はブロック内でのみ有効
  • ブロックは改行しなくてもよい
  • do ~ endの代わりに{}でもブロックを作ることができる
  • ブロック内の処理が多くなる時はdo ~ endを使う
  • ブロック内の処理が少なく、1行で書くときは{}を使う

ブロックを使う配列のメソッド

  • mapは配列の各要素を評価した結果を新しい配列として返す
  • selectは各要素をブロック内の式で評価し、真の要素のみを新しい配列として返す
  • findは各要素をブロック内の式で評価し、最初に真になった要素を返す
  • injectはたたみ込み演算をするメソッド
array = [10, 20, 30]
=> [10, 20, 30]
sum = array.inject(5) { |result, number| result += number}
=> 65
sum
=> 65

範囲(Range)

  • 範囲オブジェクトは値の範囲を表すオブジェクト(1..5や1...5のように表す)
  • 1..5は5を含む
  • 1...5は5を含まない(4.9999.....まで)
  • 範囲オブジェクトに対してメソッドを呼ぶときは範囲オブジェクトを()で囲む
  • n以上m以下、n以上m未満の判定に使うことができる
num = 10
=> 10
(1..10).include?(num)
=> true
num = 11
=> 11
(1..10).include?(num)
=> false

配列についてもっと詳しく

  • values_atを使うと、添え字を複数指定できる
  • 配列[-1]で最後の要素を取得できる(配列[-2]だと最後から2番目)
  • lastメソッドを使うと最後の要素を取得でき、引数を指定すると最後のn個の要素を取得できる
  • firstメソッドを使うと先頭の要素を取得できる
  • pushで要素を追加、deleteで要素を削除できる
  • concatは破壊的な連結、+演算子は非破壊的な連結
  • 引数名の手前に*をつけると可変長引数を使用できる(配列として受け取る)
  • ==で配列の全要素を比較できる
  • %記法で文字列の配列を作成できる
%w(dog cat bird)
=> ["dog", "cat", "bird"]
  • charsメソッドで文字列の1文字1文字を配列にできる
  • splitメソッドで指定した文字を区切り文字として文字列を配列にできる
  • 配列に初期値を設定する場合はブロックを使う(すべての要素が同一のオブジェクトに紐づくのを防ぐため)
data = Array.new(3) { 'default' }
=> ["default", "default", "default"]
data
=> ["default", "default", "default"]
str = data[1]
=> "default"
str.upcase!
=> "DEFAULT"
data
=> ["default", "DEFAULT", "default"]
  • 数値、シンボル、true/false、nilはイミュータブル

ブロックについてもっと詳しく

  • each_with_indexを使うと処理している要素の添え字を取得できる(ブロック引数の第2引数)
  • mapやdelete_ifなどで添え字付きの繰り返し処理を使うときはwith_indexを使用する
  • with_indexメソッドに引数を与えると引数の値から添え字が開始される
animals = ['dog', 'cat', 'bird']
=> ["dog", "cat", "bird"]
animals.each.with_index(5) { |animal, i| puts "#{i}: #{animal}" }
5: dog
6: cat
7: bird
=> ["dog", "cat", "bird"]

※ブロック引数で受け取る添え字が5から始まるだけで、配列から取り出されるのは0番目から
  • 配列の配列に繰り返し処理を実行すると、ブロック引数に配列が渡される
  • 上記のような繰り返し処理で、ブロック引数を配列の要素数分用意すると各要素がそれぞれ変数に代入される
  • 配列の配列にeach_with_index使うときは配列の要素を受けとるブロック引数を()で囲む
  • do endより{}の方が結合度が高い
  • 配列.map { }.join()というように書くと、mapメソッドの戻り値に対してjoinメソッドを呼び出せる(endの後ろでも可)
  • 配列のメソッドを探すときはArrayクラスとnumerableモジュールを探す

さまざまな繰り返し処理

  • 単純にn回処理を繰り返すときはtimesメソッドを使用する
sum = 0
=> 0
5.times { |n| sum += n }
=> 5
sum
=> 10
※nには012345が渡される
  • n.upto(m)でnからmまで1ずつ増やしながら繰り返し処理できる
  • n.downto(m)でnからmまで1ずつ減らしながら繰り返し処理できる
  • 始値.step(上限値, 増分)で開始値から上限値まで指定した増分を増やしながら繰り返し処理できる(増分はマイナスも可)
  • 繰り返し処理にはwhileやuntilも使用できる
  • for文もあるがRubyではeachやmap等を使うことがほとんど
  • loopメソッドで無限ループさせることができる

繰り返し処理用の制御構造

  • breakは一番内側の繰り返し処理を脱出できる
  • 外側のループまで脱出する時はthrowメソッドとcatchメソッドを使う(throw、catchはRubyでは例外処理ではない)
catch タグ名 do
  # 繰り返し処理など
  throw タグ名
end
  • throwメソッドに第2引数を渡すとcatchメソッドの戻り値になる
  • returnはメソッドからの脱出
  • nextは繰り返し処理を次に進める
  • redoは繰り返し処理をその回のみやり直す(最初からやり直すわけではない)
  • redoは使い方によっては無限ループになる可能性があるため回数制限を入れる

感想

配列の指定しない添え字を指定してもエラーにならない等、プログラムが止まらないような作りが多いことが分かった。
色々な繰り返し処理があり、使いこなせば手軽に機能を作りこめると思った。
ブロックに関してはJavaとは少し違う考え方があったので使い方に注意する。

参考文献

この記事は以下の情報を参考にして執筆しました。