配列、配列演算、繰り返し

本日の素振り。

配列

配列はArrayクラスのインスタンス。


a = Array.new(3) # [nil,nil,nil]
b = Array.new(2,"hoge")  # ["hoge","hoge"]

配列は[]で表す。


a = [10,20,30] # [10,20,30]
a[1] # 20
b = [20,true,"hoge"] # [10,true,"hoge"]
b[2] # "hoge"
b[3] # nil

%記法で配列生成

配列の要素が文字列である場合に限って、%W、%wによって文字列を配列化できる。
デリミタは半角スペース、%Wでダブルクォート、%wでシングルクォート(なし)。
自動的にダブルクォート、シングルクォートで括るため、
文字列の配列を作るためにダブルクォート、シングルクォートで汚すことを防げる。


p = %W(hoge fuga) # ["hoge","fuga"]
q = %w(hoge fuga) # ['hoge','fuga']

joinで配列結合

配列と配列を結合して新しい配列を作るのではなく、要素を文字列として結合する。


p = [100,200,300] # [100,200,300]
p.join # "100200300"
p.join("_") # "100_200_300"

配列の生成

Array.new()を使うと同じオブジェクトを持つ配列を作れる。
要素分の変数が確保されるのではなく、指定した値を持つ変数が1つ確保されて並ぶ。


a = Array.new(2,"hoge") # ["hoge", "hoge"]
a.object_id # 4032
b.object_id # 4032
a[0].replace('fuga') # ["fuga", "fuga"]
a.object_id # 4032
b.object_id # 4032

Array.new(){}だと要素数分の変数が確保されて並ぶ。


a = Array.new(2){'hoge'} # ["hoge", "hoge"]
a[0].object_id # 4033
a[1].object_id # 4034

範囲外アクセス

配列の大きさを超えてアクセスしたとき、例外とならず、アクセスしたところまで配列が広がる。
最初の位置から作った最後の位置までnilで埋められる。


a = Array.new(3){"hoge"} # ["hoge","hoge","hoge"]
a[5] = "fuga" # ["hoge","hoge","hoge",nil,nil,"fuga"]

負の添え字アクセス

何が何でもコード行を削減したい意思!
配列に負の添え字でアクセスすると”末尾から数えた位置”という意味になる。


a = ["hoge1", "hoge2", "hoge3"] # ["hoge1", "hoge2", "hoge3"]
a[-1] # "hoge3"

配列のスライス

phpのarray_slice()に相当するやつ。指定したインデックスから何個分というやつ。


a = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6]
a[2,3] # [2, 3, 4]

以下のように指定したインデックスから何個分を置き換えられる。


a = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6]
a[1,2] = "hoge" #  [0, "hoge", 3, 4, 5, 6]
b = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6]
b[1,2] = "hoge", "fuga" #  [0, "hoge","fuga", 3, 4, 5, 6]
c = [0, 1, 2, 3, 4, 5, 6] # [0, 1, 2, 3, 4, 5, 6]
c[1,2] = "hoge1", "hoge2", "hoge3" # [0, "hoge1","hoge2","hoge3", 3, 4, 5, 6]

複数の戻り返却と多重代入

複数の値を返す関数を定義する。複数の値を返すように見えるが配列が返っている。


def test
  return "hoge1", "hoge2", "hoge3"
end
a, b, c = test # ["hoge1", "hoge2", "hoge3"]
a # "hoge1"
b # "hoge2"
c $ "hoge3"

戻りとしてネストした配列を返すことができて、同じ構造の変数に代入できる。(多重代入)


def test2
  return [["hoge1", "hoge2"], "hoge3"]
end
(x,y),z = test2 # [["hoge1","hgoe2"], "hoge3"]

+、-演算子

左オペランドと右オペランドの要素の加算、左オペランドから右オペランドの減算


a = ["hoge1","hoge2"] # ["hoge1","hoge2"]
b = ["hoge2","hoge3"] # ["hoge2","hoge3"]
a + b # ["hoge1","hoge2","hoge2","hoge3"]
a - b # ["hoge1"]
b - a # ["hoge3"]

減算の場合、左オペランドに重複があるときは全て削除される


x = ["hoge1","hoge1","hoge2"] # ["hoge1","hoge2","hoge3"]
y = ["hoge1"]
x - y # ["hoge2","hoge3"]

*演算子

右オペランドが数値の場合は左オペランドをその回数繰り返す。
右オペランドが文字列の場合はjoinと同じ。


a = [1,2,3]
a * 2 # [1,2,3,1,2,3]

for式,each式

PHPのforeachに近いforとeach。forは期待と異なりループの中と外はスコープが同じ。
for内の変数をfor外でアクセスできる。


for value in [100,200,300]
  inner_loop = 500
end
inner_loop + 100 # 600

対してeachはループ内とループ外でスコープが異なりeach内の変数はeach外で未初期化。


[100,200,300].each do
  inner_look2 = 500
end
inner_loop # undefined variable