I get so confused about 2D arrays in Swift. Let me describe step by step. And would you please correct me if I am wrong.
First of all; declaration of an empty array:
class test{
var my2Darr = Int[][]()
}
Secondly fill the array. (such as my2Darr[i][j] = 0
where i, j are for-loop variables)
class test {
var my2Darr = Int[][]()
init() {
for(var i:Int=0;i<10;i++) {
for(var j:Int=0;j<10;j++) {
my2Darr[i][j]=18 /* Is this correct? */
}
}
}
}
And Lastly, Editing element of in array
class test {
var my2Darr = Int[][]()
init() {
.... //same as up code
}
func edit(number:Int,index:Int){
my2Darr[index][index] = number
// Is this correct? and What if index is bigger
// than i or j... Can we control that like
if (my2Darr[i][j] == nil) { ... } */
}
}
Before using multidimensional arrays in Swift, consider their impact on performance. In my tests, the flattened array performed almost 2x better than the 2D version:
var table = [Int](repeating: 0, count: size * size)
let array = [Int](1...size)
for row in 0..<size {
for column in 0..<size {
let val = array[row] * array[column]
// assign
table[row * size + column] = val
}
}
Average execution time for filling up a 50x50 Array: 82.9ms
vs.
var table = [[Int]](repeating: [Int](repeating: 0, count: size), count: size)
let array = [Int](1...size)
for row in 0..<size {
for column in 0..<size {
// assign
table[row][column] = val
}
}
Average execution time for filling up a 50x50 2D Array: 135ms
Both algorithms are O(n^2), so the difference in execution times is caused by the way we initialize the table.
Finally, the worst you can do is using append()
to add new elements. That proved to be the slowest in my tests:
var table = [Int]()
let array = [Int](1...size)
for row in 0..<size {
for column in 0..<size {
table.append(val)
}
}
Average execution time for filling up a 50x50 Array using append(): 2.59s
Avoid multidimensional arrays and use access by index if execution speed matters. 1D arrays are more performant, but your code might be a bit harder to understand.
You can run the performance tests yourself after downloading the demo project from my GitHub repo: https://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground
From the docs:
You can create multidimensional arrays by nesting pairs of square brackets, where the name of the base type of the elements is contained in the innermost pair of square brackets. For example, you can create a three-dimensional array of integers using three sets of square brackets:
var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
When accessing the elements in a multidimensional array, the left-most subscript index refers to the element at that index in the outermost array. The next subscript index to the right refers to the element at that index in the array that’s nested one level in. And so on. This means that in the example above, array3D[0] refers to [[1, 2], [3, 4]], array3D[0][1] refers to [3, 4], and array3D[0][1][1] refers to the value 4.
Make it Generic Swift 4
struct Matrix<T> {
let rows: Int, columns: Int
var grid: [T]
init(rows: Int, columns: Int,defaultValue: T) {
self.rows = rows
self.columns = columns
grid = Array(repeating: defaultValue, count: rows * columns) as! [T]
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> T {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
var matrix:Matrix<Bool> = Matrix(rows: 1000, columns: 1000,defaultValue:false)
matrix[0,10] = true
print(matrix[0,10])
In Swift 4
var arr = Array(repeating: Array(repeating: 0, count: 2), count: 3)
// [[0, 0], [0, 0], [0, 0]]
This can be done in one simple line.
Swift 5
var my2DArray = (0..<4).map { _ in Array(0..<) }
You could also map it to instances of any class or struct of your choice
struct MyStructCouldBeAClass {
var x: Int
var y: Int
}
var my2DArray: [[MyStructCouldBeAClass]] = (0..<2).map { x in
Array(0..<2).map { MyStructCouldBeAClass(x: x, y: $0)}
}
You should be careful when you're using Array(repeating: Array(repeating: {value}, count: 80), count: 24)
.
If the value is an object, which is initialized by MyClass()
, then they will use the same reference.
Array(repeating: Array(repeating: MyClass(), count: 80), count: 24)
doesn't create a new instance of MyClass
in each array element. This method only creates MyClass
once and puts it into the array.
Here's a safe way to initialize a multidimensional array.
private var matrix: [[MyClass]] = MyClass.newMatrix()
private static func newMatrix() -> [[MyClass]] {
var matrix: [[MyClass]] = []
for i in 0...23 {
matrix.append( [] )
for _ in 0...79 {
matrix[i].append( MyClass() )
}
}
return matrix
}
According to Apple documents for swift 4.1 you can use this struct so easily to create a 2D array:
Code sample:
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
Source: Stackoverflow.com