Swift中的多维数组

50

编辑:正如Adam Washington指出的那样,在Beta 6中,这段代码可以直接运行,所以这个问题已经不再相关。

我正在尝试创建并遍历一个二维数组:

var array = Array(count:NumColumns, repeatedValue:Array(count:NumRows, repeatedValue:Double()))

array[0][0] = 1
array[1][0] = 2
array[2][0] = 3
array[0][1] = 4
array[1][1] = 5
array[2][1] = 6
array[0][2] = 7
array[1][2] = 8
array[2][2] = 9

for column in 0...2 {
    for row in 0...2 {
        println("column: \(column) row: \(row) value:\(array[column][row])")
    }
}

然而,这是我得到的输出:

column: 0 row: 0 value:3.0
column: 0 row: 1 value:6.0
column: 0 row: 2 value:9.0
column: 1 row: 0 value:3.0
column: 1 row: 1 value:6.0
column: 1 row: 2 value:9.0
column: 2 row: 0 value:3.0
column: 2 row: 1 value:6.0
column: 2 row: 2 value:9.0

看起来最后一列的值覆盖了其他列的值。

我声明有误吗?

编辑:也许来自Playground的图片可以帮助:

从Playground获取的截图

7个回答

53

正如其他答案所述,你正在将相同的行数组添加到每一列。 要创建多维数组,必须使用循环。

var NumColumns = 27
var NumRows = 52
var array = Array<Array<Double>>()
for column in 0..NumColumns {
    array.append(Array(count:NumRows, repeatedValue:Double()))
}

10
如果您不想使用循环,可以使用以下代码:Double[][](count: NumColumns, repeatedValue:Double[](count: NumRows, repeatedValue:Double())); 这行代码创建了一个二维数组,其中包含NumColumns列和NumRows行,并将每个元素初始化为0.0。 - Literphor
3
从 beta 3 版本开始,语法略有不同。另外,这只适用于值类型数组 - 对于引用类型,您将获得对同一对象的许多引用的数组。更多信息请参见此答案 - rickster
2
多维数组初始化语法让我头疼不已,因此我写了这篇文章:http://dev.iachieved.it/iachievedit/multidimensional-arrays-in-swift/ - Joe
6
@Literphor,新的语法是[[Double]](count: NumColumns, repeatedValue:[Double](count: NumRows, repeatedValue:Double())); - Justin D.
又改了?现在看起来应该是 repeating: 而不是 repeatedValue:,而且 repeating: 显然必须放在 count: 之前。 - Victor Engel

14

给未来的读者,这里有一个优雅的解决方案(5x5):

var matrix = [[Int]](repeating: [Int](repeating: 0, count: 5), count: 5)

还有一种动态方法:

var matrix = [[Int]]() // creates an empty matrix
var row = [Int]() // fill this row
matrix.append(row) // add this row

var matrix:[[Int]] = [[Int]](repeating:[Int](repeating:0, count:5), count:5) // Swift 3变量矩阵:[[Int]] = [[Int]](重复:[Int](重复:0, 计数:5), 计数:5) // Swift 3 - FlimFlam Vir

14
var array: Int[][] = [[1,2,3],[4,5,6],[7,8,9]]

for first in array {
    for second in first {
        println("value \(second)")
    }
}

要实现你所需求的功能,你需要将数组初始化为正确的模板,然后循环添加行和列的数组:

var NumColumns = 27
var NumRows = 52
var array = Array<Array<Int>>()
var value = 1

for column in 0..NumColumns {
    var columnArray = Array<Int>()
    for row in 0..NumRows {
        columnArray.append(value++)
    }
    array.append(columnArray)
}

println("array \(array)")

是的,我看到这种声明方式可以工作,但我想声明数组而不初始化每个位。在Swift Playground中,我的声明有效,并显示了我想要的数组: [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]但是如果我输入var a = Array(count:4, repeatedValue:Array(count:3, repeatedValue:Double())) 然后a[1][1] = 99 然后a进入Playground,我得到的结果是[[0.0, 99.0, 0.0], [0.0, 99.0, 0.0], [0.0, 99.0, 0.0]] - Caroline
1
在你的数组创建中,你正在创建一个数组并重复三次相同的数组。你没有创建三个唯一的数组。 - bbarnhart
那么创建一个52行27列的多维数组的语法是什么? - Caroline
@Caroline Double[][](count: 27, repeatedValue:Double[](count: 52, repeatedValue:Double())); => @Caroline Double[][](count: 27, repeatedValue:Double[](count: 52, repeatedValue:Double())); - Literphor

6
您遇到的问题可能是由于Swift或Xcode Beta的早期版本不足造成的。如果您在2014年8月21日使用Xcode版本6.0(6A279r),则您的代码将按预期输出以下内容:
列:0 行:0 值:1.0
列:0 行:1 值:4.0
列:0 行:2 值:7.0
列:1 行:0 值:2.0
列:1 行:1 值:5.0
列:1 行:2 值:8.0
列:2 行:0 值:3.0
列:2 行:1 值:6.0
列:2 行:2 值:9.0
我刚刚将您的代码复制粘贴到一个Swift playground中,并定义了两个常量:
let NumColumns = 3,NumRows = 3

是的 - 我认为他们在那个区域做了一些改变。我已经编辑了问题。谢谢 :) - Caroline
你把println改成了print。 - Mountain Man

4

http://blog.trolieb.com/trouble-multidimensional-arrays-swift/为起点,我在我的代码中添加了泛型:

class Array2DTyped<T>{

var cols:Int, rows:Int
var matrix:[T]

init(cols:Int, rows:Int, defaultValue:T){
    self.cols = cols
    self.rows = rows
    matrix = Array(count:cols*rows,repeatedValue:defaultValue)
}

subscript(col:Int, row:Int) -> T {
    get{
        return matrix[cols * row + col]
    }
    set{
        matrix[cols * row + col] = newValue
    }
}

func colCount() -> Int {
    return self.cols
}

func rowCount() -> Int {
    return self.rows
}
}

你能解释一下'matrix[cols * row + col]'是什么意思吗? - Max_Power89
@Max_Power89 试着在纸上画一个3x3的矩阵,然后想象这个矩阵在一条线上(所以第二行在第一行的末尾,依此类推)。基本上,当你在第一列和第二行时,它与在第四个项目处是相同的。这就是cols * row + col的意思。 - Kalzem
https://github.com/qiter/swift_astarPath/blob/fee1dc501572592cf8970d79963016ef8614368d/Qt_astar/astar/Array2DTyped.swift - johndpope
这与我所做的非常相似。这种处理多维数组的特定方式仍然允许您获取数组的一维版本,如果数据集的操作与其行列位置无关,则这可能很有用。例如,如果每个单元格包含RGB像素数据,并且您想将其转换为黑白,则可以使用此方法。 - Cameron Lowell Palmer
@johndpope 在你的代码片段中,你通过遍历数组的行和列来定位一个元素。为什么不直接搜索一维版本的数组并计算行列呢?行数 = 索引 / 列数,列数 = 索引 % 列数。 - Cameron Lowell Palmer

1

您创建矩阵的原始逻辑确实是正确的,并且在Swift 2中也有效。问题在于,在打印循环中,您颠倒了行和列变量。如果将其更改为:

for row in 0...2 {
  for column in 0...2 {
    print("column: \(column) row: \(row) value:\(array[column][row])")

  }
}

你将会得到正确的结果。希望这能帮到你!

1
你正在创建一个由三个元素组成的数组,并将所有三个元素分配给同一个东西,这个东西本身也是由三个元素(三个双精度浮点数)组成的数组。
当你进行修改时,你正在修改内部数组中的浮点数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接