Ccmmutty logo
Commutty IT
5 min read

第13話 V言語の配列2

https://cdn.magicode.io/media/notebox/blob_ilfhkRh
カサレリア。katzenです。
前回、V言語の配列で、要素がたくさんあったので分けました。
今回は、引き続き配列について紹介したいと思います。
※ 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]

配列を逆順にする

  • 配列を逆順にしたい場合、reverse()を使用します。 置き換えでないためmutは必要ありません。
  • 置き換えたい場合、reverse_in_place()を使用します。 正直、統一感のない名前で、将来的に存続が心配です。
// 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]

ソート

  • そのままsort([a条件b])です。
条件でabという文字がいきなり出てくるところに注意です。変数名は固定になります。
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]

範囲取得

filtermapの他に、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!
紹介しきれませんでしたが、他にもvlib/arraysにたくさんメソッドがあります。
ついに物量に任せた配列を撃滅することに成功しました。
次回「V言語で超簡単なゲームを作る4」見てください!

Discussion

コメントにはログインが必要です。