【问题标题】:Two-dimensional array in SwiftSwift 中的二维数组
【发布时间】:2014-09-27 11:01:18
【问题描述】:

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

【问题讨论】:

  • 你的方法有问题吗?
  • 您知道,您的整个第二步可以减少到这个var my2DArray = Array(count: 10, repeatedValue: Array(count: 10, repeatedValue: 18)) 并且您真的应该升级到更新的测试版。 Int[][]() 不再是有效的语法。已改为[[Int]]()
  • 使用重复值的 2D 初始化将不起作用。所有的行都指向同一个子数组,因此不会是唯一可写的。
  • 我将一个多维数组包装在一个新结构中以获得更好的 API。

标签: arrays swift


【解决方案1】:

来自文档:

您可以通过嵌套方括号对来创建多维数组,其中元素的基本类型的名称包含在最里面的一对方括号中。例如,您可以使用三组方括号创建一个整数的三维数组:

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。

【讨论】:

    【解决方案2】:

    定义可变数组

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

    或者:

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

    或者,如果您需要一个预定义大小的数组(如 cmets 中的 @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 维数组的标记规则相同。

    【讨论】:

    • 好吧,一个愚蠢的问题:我们如何分配该数组,在 C 中我们这样做:arr[i][j]=myVar;但是当我尝试做同样的事情时,我很快就得到了这个错误“'[([(Int)])].Type'没有一个名为'subscript'的成员”
    • 如果您在答案中定义了arr,那么myVar 应该是Int,是吗?
    • 是的,它是整数。非常感谢您的详细回答.. 现在很清楚了:D
    • 在 Swift 3 中,用于复制粘贴:var arr = Int(repeating: Int(repeating: 0, count: 2), count: 3)
    • 在 Swift 4.2 中:例如 3 行 2 列 3 * 2 var arr = Array(count: 2, repeatedValue: Array(count: 3, repeatedValue: 0))
    【解决方案3】:

    在 Swift 4 中

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

    【讨论】:

      【解决方案4】:

      你在使用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
      }
      

      【讨论】:

      • 您好,我们可以将其改进为“anyObject”类型的扩展吗?
      • 关于引用类型问题的要点。但是,你为什么写Array(repeating: {value}, could 80) 并在{value} 周围加上大括号?那会创建一个闭包数组,不是吗?
      • 还是{value} 元表示法表示“AnyObject 类型的某个值”(引用类型)?
      • 因为这个问题,我花了将近一个小时寻找一个错误......
      【解决方案5】:

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

      【讨论】:

      • 我喜欢它。这让人想起 C 指针算术。不过,如果使用泛型重写会更好,因此它将适用于任何数据类型的二维数组。就此而言,您可以使用这种方法来创建任意维度的数组。
      • @vacawama,很酷,除了您的 n 维数组与使用Array(repeating:count:) 填充数组的所有解决方案存在相同的问题。请参阅我发布到您的其他答案的评论。
      【解决方案6】:

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

      【讨论】:

      【解决方案7】:

      在 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.59s

      结论

      如果执行速度很重要,请避免使用多维数组并使用索引访问。一维数组的性能更高,但您的代码可能更难理解。

      从我的 GitHub 仓库下载演示项目后,您可以自己运行性能测试:https://github.com/nyisztor/swift-algorithms/tree/master/big-o-src/Big-O.playground

      【讨论】:

        【解决方案8】:

        这可以在一行中完成。

        斯威夫特 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)}
        }
        

        【讨论】:

          【解决方案9】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-11-05
            • 2017-01-19
            相关资源
            最近更新 更多