如何更快速地转置数组?

How to transpose an array more Swiftly?

我想像这样转置一个数组:

原数组:

[
    [1,2,3],
    [4,5,6],
    [7,8,9]
]

结果:

[
    1,4,7,
    2,5,8,
    3,6,9
]
[1,4,7,2,5,8,3,6,9]

假设所有子数组的长度都相同。

如果您还没有注意到,结果中的前三项是三个子数组的第一项。结果中的第四、五、六项是每个子数组的第二项。

如果你还是不明白,也许这会有所帮助:

目前,我有这个:

func flatten(array: [[Int]]) -> [Int] {
    var flat = [Int]()
    for i in 0..<array[0].count {
        for subarray in array {
            flat.append(subarray[i])
        }
    }
    return flat
}

我认为这不是很聪明。我怎样才能快速做到这一点?

为了避免成为 XY 问题,这就是我要这样做的原因。

我正在开发棋盘游戏。我正在使用来自 HLSpriteKitHLGridNode(它基本上是网格状布局中的一堆正方形)作为棋盘游戏的棋盘。要编辑网格节点的内容,我需要传入精灵节点的一维数组,而不是二维数组。

为了让我的生活更轻松,我将模型对象存储在二维数组中。这样,我就可以通过以下方式参考左边 5 个方块和顶部 2 个方块的正方形:

modelObjects[5][2]

如果我使用 .flatMap { [=15=] } 展平 2D 数组并将结果传递给网格节点,modelObjects[5][2] 将显示为距左侧 2 个方格和距顶部 5 个方格。

这不是 this 的重复,因为该问题似乎有一定数量的数组可供使用。尽管我可以将我的二维数组放入一个循环中,并执行那些 enumerate().map {...} 的操作,但这似乎是一个非常冗长的方法。我认为必须有更简单的二维数组来做到这一点。

你可以通过转置你的二维矩阵得到你想要的结果,例如,使用这个函数:

func matrixTranspose<T>(_ matrix: [[T]]) -> [[T]] {
    if matrix.isEmpty {return matrix}
    var result = [[T]]()
    for index in 0..<matrix.first!.count {
        result.append(matrix.map{[=10=][index]})
    }
    return result
}

然后应用 flattenjoined in swift 3)。

let arr = [[1,2,3],[4,5,6],[7,8,9]]
print(matrixTranspose(arr))
// [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

print(matrixTranspose(arr).flatMap{[=11=]})
// [1, 4, 7, 2, 5, 8, 3, 6, 9]

扩展版本:

extension Collection where Self.Iterator.Element: Collection {
    var transpose: Array<Array<Self.Iterator.Element.Iterator.Element>> {
        var result = Array<Array<Self.Iterator.Element.Iterator.Element>>()
        if self.isEmpty {return result}

        var index = self.first!.startIndex
        while index != self.first!.endIndex {
            var subresult = Array<Self.Iterator.Element.Iterator.Element>()
            for subarray in self {
                subresult.append(subarray[index])
            }
            result.append(subresult)
            index = self.first!.index(after: index)
        }
        return result
    }
}

有使用

let arr = [[1,2,3],[4,5,6],[7,8,9]]
print(arr.transpose)
// [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

这是对 Shadow Of's 的改进:

extension Collection where Self.Iterator.Element: RandomAccessCollection {
    // PRECONDITION: `self` must be rectangular, i.e. every row has equal size.
    func transposed() -> [[Self.Iterator.Element.Iterator.Element]] {
        guard let firstRow = self.first else { return [] }
        return firstRow.indices.map { index in
            self.map{ [=10=][index] }
        }
    }
}

let matrix = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12],
]
matrix.transposed().forEach{ print([=10=]) }