カサレリア。katzenです。
今回は、引き続き配列について紹介したいと思います。
※ arraysのmut系はreplでは意図した動作にならないみたいです。ファイルにして実行しましょう。
配列にデータを挿入する
この場合、新しい配列が作られるのではなく、指定された配列が操作対象です。そのためmut
が必要になります。
-
指定位置に挿入したい場合、insert(<index>, <データ>)
を使用します。
-
配列の先頭に追加したい場合、prepend(<データ>)
を使用します。insert(0,<データ>)
と同じ結果になります。
データは同じ型なら、配列でもプリミティブでも追加できます。
// day12-insert-prepend.v
mut a := [1,2,3]
b := [-3,-2,-1]
a.prepend(b)
a.insert(3,0)
println(a)
// [-3,-2,-1,0,1,2,3]
要素を消す
この場合、新しい配列が作られるのではなく、指定された配列が操作対象です。そのためmut
が必要になります。
-
指定範囲を消す場合、delete_many(<index>,<size>)
です。
-
前方から指定要素数にしたい場合、trim(<size>)
です。
delete_many(0,<size>)
と同じ結果になります。
-
指定要素を消したい場合、delete(<index>)
です。
delete_many(<index>,1)
と同じ結果になります。
-
最後の要素を消したい場合、delete_last()
です。
delete_many(<配列>.len-1,1)
と同じ結果になります。
効率はともかく、dalete_many
さえ覚えれば、同じ結果を得られます。
// day12-delete.v
mut a := [1,2,3,4,5,6,7]
a.delete_many(4,3)
println(a)
// [1, 2, 3, 4]
a.trim(3)
println(a)
// [1, 2, 3]
a.delete(1)
println(a)
// [1, 2,]
a.delete_last()
println(a)
// [1]
配列を逆順にする
// day12-reverse.v
mut a := [1,2,3]
b := a.reverse()
println(a) // [1,2,3]
println(b) // [3,2,1]
a.reverse_in_place()
println(a) // [3,2,1]
ソート
条件でa
とb
という文字がいきなり出てくるところに注意です。変数名は固定になります。
mut a:= [1,3,2,5,4]
a.sort()
println(a) // [1,2,3,4,5]
a.sort(b < a)
println(a) // [5,4,3,2,1]
範囲取得
filter
やmap
の他に、V言語にはslice
という考え方があります。
少し癖があり、メモリについて知識がないと理解が難しいかもしれません。
例を見つつコメントを書きます。
// day12-slice.v
a := [1,2,3,4,5]
mut b := a[1..3] // 1から3までの要素を取得
println(a) // [1,2,3,4,5]
println(b) // [2,3]
b[1] = -1
println(a) // [1,2,-1,4,5] -1になっていることに注意
println(b) // [2,-1]
b << 9
println(a) // [1,2,-1,4,5] // ここは変化しません。
println(b) // [2,-1,9]
b[0] = -9
println(a) // [1,2,-1,4,5] // ここは変化しません。
println(b) // [-9,-1,9]
おわかりいただけたでしょうか。
bに-1を代入したときmut
ではない、aの要素が書き換わっています。
つまりslice
はアドレス参照ということになります。
しかしb<<9以降はどうでしょう。aには変化がありません。
配列にはcap
というものがあったことを覚えていますでしょうか。
データ量がcapを超えると必要メモリを新たに確保して、値をコピーする動作が入ります。
これでaとはメモリアドレスが変わるため、aに値が反映されないのでこのような動作になります。
slice
は他の配列操作と違ってマイナス
が使用できます。
この際、#[<start>..<end>]
と#
がつくことになります。
正直不思議ですね。普通にかければいいのですが。
x := [1,2,3,4,5]
println(x#[-3..]) // [3,4,5] 後ろ3番目から最後まで
println(x#[-9..]) // [1,2,3,4,5] 後ろ9番目から最後まで
println(x#[-9..-5]) // [] 後ろ9番目から後ろから5番目まで
println(x#[..-3]) // [1,2] 最初から後ろから3番目まで
と範囲外を指してもエラーにはなりません。空の配列が返ります。
連想配列
書き方はほぼgolangと一緒です。
この場合もmap
という名前でメソッドに同じ名称なので紛らわしいですが、そういうものだと諦めましょう。
color := {'red': 0xff00, 'green': 0x00ff00, 'blue': 0x0000ff}
println(color['red']) // 65280
mut m := map[string]int{}
m['one'] = 1
m['two'] = 2
println(m['two']) // 2
println(m['four']) // 0 存在しないキー
println('four' in m) // false 存在しないキー
println(m.keys()) // ['one', 'two']
m.delete("one")
範囲外インデックスのキャッチ
代入の際はor
を用いてエラーを処理できるようです。
w := [0,0,0]
v := w[2] or { -1 }
println(v) // 0
y := w[9] or { -1}
println(y) // -1
z := w[99] or { panic("out of range")} // panic!