Swiftではこんな感じにサブスクリプトを使うことで多次元配列っぽい構造体を作れる。
これをさらに汎用的にして多次元配列の機能を再現させてみたい。
(それなら多次元配列を使えばいいじゃないかという声が聞こえてきそう。)
board.swift
struct Board{
var size:[Int]
var data: [Float]
init(x:Int ,y:Int){
size=[Int](count: 2, repeatedValue: 0)
size[0]=x
size[1]=y
data = [Float](count: x * y, repeatedValue: 0.0)
}
func indexIsValid(x:Int, y:Int) -> Bool{
return x>=0 && x<size[0] && y>=0 && y<size[1]
}
subscript(x:Int,y:Int) -> Float{
get{
assert(indexIsValid(x,y: y),"index out of range")
return data[x + y * size[0]]
}
set{
assert(indexIsValid(x,y:y),"index out of range")
data[x + y * size[0]] = newValue
}
}
}
var b = Board(x: 3,y: 3)
b[1,1] = 1
上の2次元配列っぽいものを3次元配列に拡張してみる。
ジェネリクスで型指定も可能にしてみた。
これなら3次元グリッドを表現する場合に実際に使えそうだ。
あと一般化するための規則性も見えてきた。
grid.swift
struct Grid<T>{
var size:[Int]
var data: [T?]
init(x:Int ,y:Int, z:Int){
size=[Int](count: 3, repeatedValue: 0)
size[0]=x
size[1]=y
size[2]=z
data = [T?](count: x * y * z, repeatedValue: nil)
}
func indexIsValid(x:Int, y:Int, z:Int) -> Bool{
return x>=0 && x<size[0] &&
y>=0 && y<size[1] &&
z>=0 && z<size[2]
}
subscript(x:Int,y:Int,z:Int) -> T{
get{
assert(indexIsValid(x,y:y,z:z),"index out of range")
return data[x + y * size[0] + z * size[0] * size[1]]!
}
set{
assert(indexIsValid(x,y:y,z:z),"index out of range")
data[x + y * size[0] + z * size[0] * size[1]] = newValue
}
}
}
var g = Grid<Float>(x: 10, y: 10, z: 10)
g[1,1,1] = 1
上を元にしてさらに汎用的にして多次元配列っぽくしてみる。
これならIntの範囲の大きさで任意の次元の配列も扱うことができるはずだ。
いつ役に立つか分からないけど、いつか役立つことを信じてみます。
MultiArray.swift
class MultiArray<T>{
var size:[Int]
var data: [T?]
init(size:Int...){
self.size = size
let multiply = { (a:Int, b:Int) -> Int in a * b}
data = [T?](count: size.reduce(1,combine: multiply), repeatedValue: nil)
}
func indexIsValid(indeces:[Int]) -> Bool{
var v:Bool = true
for (i,index) in indeces.enumerate() {
v = v && index>=0 && index<size[i]
}
return v
}
func createIndex(n:[Int]) -> Int{
var index:Int = 0
for (i,v) in n.enumerate(){
var s:Int = 1
for j in 0..<i{
s *= size[j]
}
index += v * s
}
return index
}
subscript(n:Int...) -> T{
get{
assert(indexIsValid(n),"index out of range")
return data[createIndex(n)]!
}
set{
assert(indexIsValid(n),"index out of range")
data[createIndex(n)] = newValue
}
}
}
var mf = MultiArray<Float>(size:10,10,10)
mf[1,1,1] = 1
var ms = MultiArray<String>(size:1,2,3,4)
ms[1,1,1,1]="a"
※createIndexの所はもう少し関数型っぽく書けそう。