我试图解决这个挑战:给定组大小的组反转一系列元素.
给定数组:[1,2,3,4,5,6]
期望的结果(组大小为3):[4,5,6,1,2,3]
如果最后一个组的元素少于组大小,则只需添加它们并完成,如下所示:
给定数组:[1,2,3,4,5,6,7]
期望的结果:[ 5,6,7,2,3,4,1 ]
我试过这个并且它正在工作,但对我来说它看起来有点奇怪.任何人都可以帮我找到更清洁或更直观的解决方案吗?
extension Array {
func reverse(groupSize: Int) -> [Element] {
var reversed = [Element]()
let groups = count / groupSize
for group in 0...groups {
let lowerBound = count - group * groupSize - groupSize
let upperBound = count - 1 - group * groupSize
if lowerBound >= 0 {
reversed += Array(self[lowerBound...upperBound])
} else {
reversed += Array(self[0...upperBound])
}
}
return reversed
}
}
Run Code Online (Sandbox Code Playgroud)
你可以说:
extension Array {
func groupedReversing(stride: Int) -> [Element] {
precondition(stride > 0, "stride must be > 0")
return Swift.stride(from: count, to: 0, by: -stride)
.flatMap { self[Swift.max(0, $0 - stride) ..< $0] }
}
}
let result = Array(1 ... 7).groupedReversing(stride: 3)
print(result) // [5, 6, 7, 2, 3, 4, 1]
Run Code Online (Sandbox Code Playgroud)
我们用来stride(from:through:by:)
以(减去)步幅的增量从array.count
(包含)到(排除)迭代。0
该Swift.
前缀是为了消除它与过时的 Swift 2stride
方法的歧义(该方法将在 Swift 4.1 中消失)。
然后,我们将索引平面映射到输入数组的一个切片,该stride
切片的长度最多为元素(当我们将较低的索引限制为 0 时,在数组的开头截断)。因为这是flatMap
,所以生成的切片将连接成单个结果数组。
Sequence
您还可以通过首先提供 的实现BidirectionalCollection
、向后推进索引并将切片附加到结果数组中来实现完全通用的版本:
extension BidirectionalCollection {
func groupedReversing(stride: Int) -> [Element] {
precondition(stride > 0, "stride must be > 0")
var result: [Element] = []
result.reserveCapacity(numericCast(count))
var upper = endIndex
while upper != startIndex {
// get the next lower bound for the slice, stopping at the start index.
let lower = index(upper, offsetBy: -numericCast(stride),
limitedBy: startIndex) ?? startIndex
result += self[lower ..< upper]
upper = lower
}
return result
}
}
Run Code Online (Sandbox Code Playgroud)
然后实现一个重载,Sequence
首先转换为数组,然后转发到上面的实现:
extension Sequence {
func groupedReversing(stride: Int) -> [Element] {
return Array(self).groupedReversing(stride: stride)
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以调用它,例如 a,CountableClosedRange
而无需先将其转换为数组:
let result = (1 ... 7).groupedReversing(stride: 3)
print(result) // [5, 6, 7, 2, 3, 4, 1]
Run Code Online (Sandbox Code Playgroud)