如何更快速地转置数组?
Posted
技术标签:
【中文标题】如何更快速地转置数组?【英文标题】:How to transpose an array more Swiftly? 【发布时间】:2017-02-14 19:40:05 【问题描述】:我想像这样转置一个数组数组:
原始数组:
[
[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 问题,这就是我想要这样做的原因。
我正在开发一款棋盘游戏。我正在使用来自HLSpriteKit 的HLGridNode
(它基本上是一堆网格状布局的正方形)作为棋盘游戏的棋盘。要编辑网格节点的内容,我需要传入精灵节点的一维数组,而不是二维数组。
为了让我的生活更轻松,我将模型对象存储在二维数组中。这样,我可以通过执行以下操作来引用左侧 5 个正方形和顶部 2 个正方形的正方形:
modelObjects[5][2]
如果我使用 .flatMap $0
展平二维数组并将结果传递给网格节点,modelObjects[5][2]
将显示为距左侧 2 个正方形,距顶部 5 个正方形。
这不是this 的副本,因为该问题似乎有一定数量的数组可供使用。虽然我可以将我的二维数组放入一个循环中,然后做那些enumerate().map ...
的东西,但这似乎是一个非常冗长的方法。我认为必须有一个更简单的方法来使用 2D 数组。
【问题讨论】:
Combining multiple arrays into one, indexing sequentially的可能重复 “我正在开发一款棋盘游戏。”这就是您要解决的问题。你已经解决了数组问题。再花时间在它上面会分散你真正目标的注意力。这并不是说这个问题不有趣。解决问题并不重要。 重新编辑:快速浏览一下“重复的候选者”,在我看来,它的答案不假设有一定数量的数组可以使用。 (同意重复标记)注意:您似乎想要转置给定的二维数组,然后简单地展平转置后的数组。看看SwiftSequence 库,它就包含这样一个转置函数(尽管是 Swift 2)。 【参考方案1】:这是对Shadow Of的answer的改进:
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 $0[index]
let matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
matrix.transposed().forEach print($0)
【讨论】:
只有在扩展中才能成为 Swifty ;) 当我尝试编写扩展时,我很生气。尝试使用map
导致“分段错误”而没有明显的原因,尝试使用indicies
导致烦人的“无法下标”.. 最后我得到了这个工作版本。我知道如何在 swift 2 中编写它,但是在 swift 3 中它看起来很丑。你能看看我更新的答案,并指出一些错误或更简单的方法吗?
稍后让我试一试
鉴于 OP 希望将 2D 数组展平和转置,您可以将第一个 map
更改为 flatMap
- 然后返回 [T]
;)
@Hamish 是的,那他会更适合 OP 的问题,但最好让答案的组成部分保持通用和可重用【参考方案2】:
你可以通过转置你的二维矩阵得到你想要的结果,例如,使用这个函数:
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$0[index])
return result
然后应用flatten
(joined
在 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$0)
// [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]]
【讨论】:
尽量避免0 ..< array.count
。您可以使用array.indices
。看看我对你的回答的改进。
如果您为Array
进行扩展,您应该能够添加约束Element.Indices.Iterator.Element == Element.Index
(参见this Q&A)并使用@AlexanderMomchliov 的扩展实现(替换matrix
self
)。以上是关于如何更快速地转置数组?的主要内容,如果未能解决你的问题,请参考以下文章