CO fans: before you jump into conclusion it is a duplicate, there are 2 distinct flavours of arrays, and it seems I am asking about less popular one.
So far, I
Yes, there is nothing built-in (as far as I know). You can define a custom class/struct (as in Most efficient way to access multi-dimensional arrays in Swift?
or How to Declare a Multidimensional Boolean array in Swift?) with a subscript operator, so that a[0,0] = 1
works.
Here is a mixture of those solutions, but as a
generic struct
instead of class
. I have also changed the order of
the rows and columns parameters because I find that more natural:
struct Array2D<T : IntegerLiteralConvertible > {
let rows : Int
let cols : Int
var matrix: [T]
init(rows : Int, cols : Int) {
self.rows = rows
self.cols = cols
matrix = Array(count : rows * cols, repeatedValue : 0)
}
subscript(row : Int, col : Int) -> T {
get { return matrix[cols * row + col] }
set { matrix[cols*row+col] = newValue }
}
}
I don't see how to create such a thing from a literal like
[2, 3 ;; -1, 0]
. But you could initialize it from a nested array:
extension Array2D {
init(_ elements: [[T]]) {
let rows = elements.count
let cols = elements[0].count
self.init(rows: rows, cols: cols)
for i in 0 ..< rows {
assert(elements[i].count == cols, "Array must have same number of elements for each row")
self.matrix.replaceRange(cols * i ..< cols * (i+1), with: elements[i])
}
}
}
Example:
let array = Array2D([[1, 2, 3], [4, 5, 6]])
println(array.rows) // 2
println(array.cols) // 3
println(array[1, 2]) // 6
println(array[1, 0]) // 4
You can additionally implement the ArrayLiteralConvertible
protocol to initialize a 2d array from a nested array literal:
extension Array2D : ArrayLiteralConvertible {
init(arrayLiteral elements: [T]...) {
self.init(elements)
}
}
Example:
let array : Array2D = [[1, 2, 3], [4, 5, 6]]
For square arrays (rows == columns
) you could alternatively initialize it from a plain array:
extension Array2D {
init(_ elements: [T]) {
let rows = Int(sqrt(Double(elements.count)))
assert(rows * rows == elements.count, "Number of array elements must be a square")
self.init(rows: rows, cols: rows)
self.matrix = elements
}
}
Example:
let squareArray = Array2D([2, 3, -1, 0])
println(squareArray.rows) // 2
println(squareArray.cols) // 3
println(squareArray[1, 0]) // -1
An example implementation supporting arbitrary number of dimensions:
struct ArrayMultiDimension<T> {
private var _base:[T]
let _dimensions: [Int]
init(initialValue: T, dimensions:Int...) {
_base = Array(count: reduce(dimensions, 1, *), repeatedValue: initialValue)
_dimensions = dimensions
}
private func _position2idx(position:[Int]) -> Int {
assert(position.count == _dimensions.count)
return reduce(Zip2(_dimensions, position), 0) {
assert($1.0 > $1.1)
return $0 * $1.0 + $1.1
}
}
subscript(position:Int...) -> T {
get { return _base[_position2idx(position)] }
set { _base[_position2idx(position)] = newValue }
}
}
// Usage:
var array3d = ArrayMultiDimension(initialValue: "", dimensions: 4,3,2)
for x in 0 ..< 4 {
for y in 0 ..< 3 {
for z in 0 ..< 2 {
array3d[x,y,z] = "\(x)-\(y)-\(z)"
}
}
}
array3d[1,2,0] = "foo"
But, this could be very slow...