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]?

9
  • I believe this is already answered in this thread. stackoverflow.com/questions/25127700/… Commented Mar 9, 2015 at 7:26
  • 1
    @PrashanthDs, nope. The linked question is about jagged arrays. Commented Mar 9, 2015 at 7: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? Commented Mar 9, 2015 at 7:36
  • 1
    This might help: stackoverflow.com/questions/27139437/…, stackoverflow.com/a/28892107/1187415. Commented Mar 9, 2015 at 7:41
  • 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]. Commented Mar 9, 2015 at 7:49

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.