按组大小反转数组

Oxt*_*hor 9 arrays swift

我试图解决这个挑战:给定组大小的组反转一系列元素.

给定数组:[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)

Ham*_*ish 1

你可以说:

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(包含)到(排除)迭代。0Swift.前缀是为了消除它与过时的 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)