0

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 saw only syntax for jagged arrays like [[Int]], but I couldn't find any info about flat multidimensional arrays. So what is the syntax for type (like 2d array of Ints) and what is the syntax of initializing such array with data? Is there any [2, 3 ;; -1, 0]?

greenoldman
  • 16,895
  • 26
  • 119
  • 185
  • I believe this is already answered in this thread. http://stackoverflow.com/questions/25127700/two-dimension-array-in-swift – Prashanth Ds Mar 09 '15 at 07:26
  • 1
    @PrashanthDs, nope. The linked question is about jagged arrays. – greenoldman Mar 09 '15 at 07:29
  • 2
    I don't believe Swift supports true multidimensional arrays at this time. Is it just a neater syntax you're looking to adopt, or is there another reason jagged arrays aren't suitable for what you're trying to do? – Stuart Mar 09 '15 at 07:36
  • @Stuart, multidimensional arrays are pretty basic and old concept so I want to learn about syntax, no dark secrets here :-). Can you post your comment as an answer? Thank you. – greenoldman Mar 09 '15 at 07:39
  • 1
    This might help: http://stackoverflow.com/questions/27139437/most-efficient-way-to-access-multi-dimensional-arrays-in-swift, http://stackoverflow.com/a/28892107/1187415. – Martin R Mar 09 '15 at 07:41
  • @MartinR, I am just asking about the syntax, nothing more. It looks Swift does not support those arrays indeed. Pity. – greenoldman Mar 09 '15 at 07:43
  • 2
    Yes, there is nothing built-in (as far as I know). You can define a custom class/struct (as in the linked threads) with a subscript operator, so that `a[0,0] = 1` works. But I don't see how to create such a thing with a literal like `[2, 3 ;; -1, 0]`. For square arrays (rows == columns) you could implement the ArrayLiteralConvertible protocol and then initialize it from `[2, 3, -1, 0]`. – Martin R Mar 09 '15 at 07:49
  • @MartinR, could you please move your comment as an answer? I can upvote the comment, but I cannot accept it (closing the question). – greenoldman Mar 09 '15 at 07:51
  • @greenoldman: Done, and added some code with a possible alternative. – Martin R Mar 09 '15 at 08:50

2 Answers2

4

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
Community
  • 1
  • 1
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
0

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...

rintaro
  • 51,423
  • 14
  • 131
  • 139