- Rubyの配列について詳しく知りたい。
Rubyのシルバー試験を受験したのですが、配列に対する問題が多めでした。
合格はどうにか出来ましたが、実務でもちゃんと使えるよう記事にまとめます。
また、同様にRubyのシルバー試験を受験している方の手助けできれば幸いです^^
配列の生成方法
配列は、Arrayクラスのインスタンス。
配列の各要素にそれぞれ異なった型の変数を指定できる。
配列の配列(多次元配列)も実現できる。
[]を使う
配列を簡単に生成するにはコレが一番手取り早い
# []を使って配列を生成
a = []
p a #= > []
# それぞれ異なった型を配列に入れれる
b = [10, false, "abc"]
p b #=> [10, false, "abc"]
# 二次元配列も可能
c = [[1, 2],["a", "b"],[true, false]]
p c #=> [[1, 2], ["a", "b"], [true, false]]
パーセント記法を使う
%w、%Wを使って配列を生成する方法。
要素の文字列はダブルクォートやカンマで区切らずに、空白で区切って記述する。
- %w:シングルクォートで配列を生成する。そのため、式展開は行われない。
- %W:ダブルクォートで配列を生成する。
# シングルクォートで配列を作成する
a = %w(hoge#{1 + 2} 1 false)
p a #>= ["hoge\#{1", "+", "2}", "1", "false"]
# ダブルクォートで配列を作成する
c = %W(hoge#{1 + 2} 1 false)
p c #>= ["hoge3", "1", "false"]
# joinメソッドで区切りのある文字列を生成したい場合に便利
p c.join("-") #>= "hoge3-1-false"
Arrayクラスを使って生成する
Array[]を使って生成する
# Array[]を使った方法
z = Array[1,2,3]
p z #=> [1, 2, 3]
Array.newを使って生成する
第1引数:配列の長さ。
第2引数:デフォルト値。ブロックで指定することも可能。
第2引数を省略した場合。配列の長さのみ確保され、中身はnilになる。
a = Array.new(3)
p a #=> [nil, nil, nil]
p a.length #=> 3
第2引数に、初期値を設定した場合
初期値オブジェクトは全て同一のオブジェクトになるため注意が必要!!
# 初期値も設定した場合
b = Array.new(3, "b")
# 初期値オブジェクトは全て同一のオブジェクトになるため注意
p b #>= ["b", "b", "b"]
# オブジェクトIDが同一になっている
p b[0].object_id #>= 70143624257420(値は実行環境によって異なる)
p b[1].object_id #>= 70143624257420
p b[2].object_id #>= 70143624257420
b[0].replace("B")
#全ての値がreplaceされてしまう
p b #>= ["B", "B", "B"]。["B", "b", "b"]とはならない。
c = Array.new(3, "c")
p c #>= ["c", "c", "c"]
# [0]以外で指定しても同様
c[1].replace("C")
p c #>= ["C", "C", "C"]。["c", "C", "C"]とはならない。
d = Array.new(4, "d")
p d #>= ["d", "d", "d"]
p d[0].object_id #>= 70113823431360
p d[1].object_id #>= 70113823431360
p d[2].object_id #>= 70113823431360
p d[3].object_id #>= 70113823431360
# 値を上書きする
d[0] = "D"
d[2] = "D"
p d[0].object_id #>= 70113823430820
p d[2].object_id #>= 70113823430800
p d #>= ["D", "d", "D", "d"]
d[0].replace("Z")
p d #>= ["Z", "d", "D", "d"]。オブジェクトIDが変わってしまったため、["Z", "d", "Z", "d"]とはならない。
d[1].replace("Y")
p d #>= ["Z", "Y", "D", "Y"]。[1,3]は、オブジェクトIDが同じなので一緒に変わってしまう
初期値をブロックで指定した場合
第2引数で直接デフォルト値を設定した場合と違い、オブジェクトIDが異なるため上書き更新の心配がない
# ブロックで初期値を設定する
e = Array.new(3) { |i| "b: #{i} " }
p e #>= ["b: 0 ", "b: 1 ", "b: 2 "]
# ブロックで初期値を設定した場合は、オブジェクトIDが異なる
p e[0].object_id #>= 70139110773360
p e[1].object_id #>= 70139110773320
p e[2].object_id #>= 70139110773280
#b[1] = 10
e[0].replace("10")
p e #>= ["10", "b: 1 ", "b: 2 "]
配列の代入
配列のサイズは要素への代入によって動的に変わる。
上限を超えた場合はnilを返す。
a = [1]
p a.length #> = 1
# サイズを超えて
a[3] = "3"
p a.length #> = 4
#
p a #> = [1, nil, nil, "3"]
# 取得内容
p a[3] #> = "3"
p a[2] #> = nil
# 範囲を超えて指定してもエラーにはならない
p a[100] #> = nil
配列の添字
[]の中身の指定方法あれこれ。負の値
末尾の要素を-1として先頭に向かって順に減っていく
正の値は、0からスタートとなっているので注意。
a = [1,2,3,4,5]
# 負の値は末尾からスタート。-1始まり
p a[-1] #>= 5
# 正の値は先頭からスタート。0始まり
p a[0] #>= 1
# 配列の中で計算した結果を指定。3で検索している
p a[4-1] #>= 4
p a[-5] #>= 1
# 範囲外の値を指定するとnilで返却
p a[-100] #>= nil
要素数を指定
添字に2つの指定をして範囲を設定する。
1つ目の添字が、インデックスを指定。
2つ目の添字が、1つ目で指定したインデックスから何個の要素数かを示す。
a = [1,2,3,4,5]
# インデックス2から3までを示す訳ではないので[2,3]ではない!
p a[2,3] # >= [3,4,5]
# 1 2 3 4 5 要素
# 0 1 2 3 4 インデックス
# ↑ ここから3つ指定
配列についてはシルバー試験で結構問われます。
特に、この要素の指定方法と範囲リテラルの使い分けについてはよく出題されましたので注意を。
- 1..10 :10以下。つまり、1~10まで。
- 1…10 :10未満。つまり、1~9まで。
上の要素を指定した場合との比較が以下の例。
a = [1,2,3,4,5]
# 2以下。つまり、2~3の範囲
p a[2..3] #>= [3, 4]
# 2未満。つまり、2。
p a[2...3] #>= [3]
範囲の指定は、2つの要素に1つ目の値から何個の要素を取るか?
に対して、範囲リテラルは、全てインデックスの範囲を取ります。
?な人は、上記の例をよく見比べてみてください。
要素数を指定した代入について
要素数を指定して代入すると、その範囲部分がまとめて置き換わる
a = [1,2,3,4,5]
a[1,2] = "A"
# [2,3]の指定部分まとめて"A"に置き換わる
p a #> [1, "A", 4, 5]
b = [1,2,3,4,5]
# 複数値を指定することもできる
b[1,2] = ["A","B"]
p b #>= [1, "A", "B", 4, 5]
c = [1,2,3,4,5]
# []を省略して複数指定も可能
c[1,2] = "A", "B"
# bの配列と同じ結果
p c #>= [1, "A", "B", 4, 5]
d = [1,2,3,4,5]
# 指定した数以上の値を代入してしまった場合
d[1,2] = "A","B","C"
# 余った要素も代入される
p d #>= [1, "A", "B", "C", 4, 5]
# 少ない場合は、aの配列と同じ結果になる
まとめ
- 配列の生成
- 配列の代入
- 配列の添字について
以上についてまとめました!
配列のメソッド(Arrasyクラスのメソッド)については、かなり長くなりそうだったので今回は割愛。
基本の基本だけまとめたつもりです。
参考書籍はこちら。
Gold受験のために購入したのですが、結構細かいところまで乗っていてかなり勉強になりました。
記事の内容は、この書籍を参考にした内容にプラスして、「こう変えたらどうなる?」ってのを自分なり考えたソースコードを記載してます。
Rubyは奥が深いですねー。
色々と好きなようにカスタマイズできる反面、メソッドの挙動についてよくよく調べておかないとバグの元になりそうです。
一旦、Goldの合格を目指してますが合格してからも引き続き勉強しよっかな。。。