簡體   English   中英

Swift 中的二維數組

[英]Two-dimensional array in Swift

我對 Swift 中的二維數組感到非常困惑。 讓我一步一步描述。 如果我錯了,請您糾正我。

首先; 空數組的聲明:

class test{
    var my2Darr = Int[][]()
}

其次填充數組。 (例如my2Darr[i][j] = 0其中 i, j 是 for 循環變量)

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?  */
            }
        }
    }
}

最后,編輯數組中的元素

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) { ...  }   */
    }
}

定義可變數組

// 2 dimensional array of arrays of Ints 
var arr = [[Int]]() 

或者:

// 2 dimensional array of arrays of Ints 
var arr: [[Int]] = [] 

或者,如果您需要一個預定義大小的數組(如評論中 @0x7fffffff 所述):

// 2 dimensional array of arrays of Ints set to 0. Arrays size is 10x5
var arr = Array(count: 3, repeatedValue: Array(count: 2, repeatedValue: 0))

// ...and for Swift 3+:
var arr = Array(repeating: Array(repeating: 0, count: 2), count: 3)

改變位置的元素

arr[0][1] = 18

或者

let myVar = 18
arr[0][1] = myVar

更改子數組

arr[1] = [123, 456, 789] 

或者

arr[0] += 234

或者

arr[0] += [345, 678]

如果在這些更改之前您有 0(零)的 3x2 數組,那么現在您有:

[
  [0, 0, 234, 345, 678], // 5 elements!
  [123, 456, 789],
  [0, 0]
]

因此請注意,子數組是可變的,您可以重新定義表示矩陣的初始數組。

訪問前檢查大小/邊界

let a = 0
let b = 1

if arr.count > a && arr[a].count > b {
    println(arr[a][b])
}

備注: 3 維和 N 維數組的標記規則相同。

從文檔:

您可以通過嵌套方括號對來創建多維數組,其中元素的基本類型的名稱包含在最里面的一對方括號中。 例如,您可以使用三組方括號創建一個整數的三維數組:

var array3D: [[[Int]]] = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]

訪問多維數組中的元素時,最左邊的下標索引指的是最外層數組中該索引處的元素。 右邊的下一個下標索引指的是嵌套在數組中該索引處的元素。依此類推。 這意味着在上面的例子中,array3D[0] 指的是 [[1, 2], [3, 4]],array3D[0][1] 指的是 [3, 4],array3D[0][1 ][1] 指的是值 4。

使其通用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])

使用Array(repeating: Array(repeating: {value}, count: 80), count: 24)時應該小心。

如果值是一個由MyClass()初始化的對象,那么它們將使用相同的引用。

Array(repeating: Array(repeating: MyClass(), count: 80), count: 24)不會在每個數組元素中創建MyClass的新實例。 此方法只創建一次MyClass並將其放入數組中。

這是一種初始化多維數組的安全方法。

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
}

在斯威夫特 4

var arr = Array(repeating: Array(repeating: 0, count: 2), count: 3)
// [[0, 0], [0, 0], [0, 0]]

根據 swift 4.1 的 Apple 文檔,您可以輕松地使用此結構來創建 2D 數組:

鏈接: https ://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Subscripts.html

代碼示例:

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

在 Swift 中使用多維數組之前,請考慮它們對性能的影響 在我的測試中,扁平陣列的性能幾乎是 2D 版本的 2 倍:

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

填充 50x50 數組的平均執行時間:82.9ms

對比

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

填充 50x50 2D 數組的平均執行時間:135ms

兩種算法都是 O(n^2),所以執行時間的差異是由我們初始化表的方式造成的。

最后,你能做的最糟糕的事情是使用append()添加新元素。 在我的測試中,這被證明是最慢的:

var table = [Int]()    
let array = [Int](1...size)
for row in 0..<size {
    for column in 0..<size {
        table.append(val)
    }
}

使用 append() 填充 50x50 數組的平均執行時間:2.59 秒

結論

如果執行速度很重要,請避免使用多維數組並使用索引訪問。 一維數組的性能更高,但您的代碼可能更難理解。

從我的 GitHub 存儲庫下載演示項目后,您可以自己運行性能測試: https ://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground

這可以在一個簡單的行中完成。

斯威夫特 5

var my2DArray = (0..<4).map { _ in Array(0..<) }

您還可以將其映射到您選擇的任何類或結構的實例

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)}
}

斯威夫特 5.5 版

這個版本使用一個底層的可選數組來避免由使用斷言引起的運行時意外。

struct Matrix<T> {
  let numberOfRows: Int
  let numberOfColumns: Int
  
  var elements: [T?]
  
  /// Creates a new matrix whose size is defined by the specified number of rows and columns.
  /// containing a single, repeated optional value.
  ///
  ///  - Parameters:
  ///    - repeatedValue: The element to repeat
  ///    - numberOfRows: The number of rows
  ///    - numberOfColumns: The number of columns
  init(repeating repeatedValue: T? = nil, numberOfRows: Int, numberOfColumns: Int) {
    // counts must be zero or greater.
    let numberOfRows = numberOfRows > 0 ? numberOfRows : 0
    let numberOfColumns = numberOfColumns > 0 ? numberOfColumns : 0
    
    self.numberOfRows = numberOfRows
    self.numberOfColumns = numberOfColumns
    self.elements = Array(repeating: repeatedValue, count: numberOfRows * numberOfColumns)
  }
  
  subscript(row: Int, column: Int) -> T? {
    get { elements[(row * numberOfColumns) + column] }
    set { elements[(row * numberOfColumns) + column] = newValue }
  }
}

我會使用一維數組並單獨索引它。 例如考慮使用:

struct MatrixIndexer {
    var rows: Int
    var columns: Int
    
    var count: Int {
        return rows * columns
    }
    
    subscript(_ r: Int, _ c: Int) -> Int {
        precondition(r < rows && c < columns)
        return r * columns + c
    }
    
    func coordinate(_ i: Int) -> (row: Int, column: Int) {
        precondition(i < count)
        return (i / columns, i % columns)
    }
}

let at = MatrixIndexer(rows: 16, columns: 8)
var array2D: [Float] = Array(repeating: 0, count: at.count)

array2D[at[3, 4]] = 3
array2D[at[5, 2]] = 6

(如果你想傳遞一個單一的結構,你可以引入一個包含Array2D和一個ArrayMatrixIndexer )。

為什么這是個好主意? 首先,您可以獲得更好的開箱即用操作,例如:

  • 集合擴展:map、filter、reduce
  • 在單個循環中迭代所有元素
  • 輕松復制
  • 保證每行每列大小相同的不變量

其次,它的性能也好得多。

  • 通過減少內存分配來加快訪問時間。 每個元素與下一個元素是連續的,而不是每一行都是內存中的一個單獨的點。
  • 使用一個分配和釋放命令而不是多個(分配器通常由於各種原因很慢)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM