按组大小反转数组

时间:2017-12-27 08:38:59

标签: 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
    }
}

4 个答案:

答案 0 :(得分:2)

以下解决方案基于stride + map

的组合
let groupSize = 3
let array = [1, 2, 3, 4, 5, 6]
let reversedArray = Array(array.reversed())
let result = stride(from: 0, to: reversedArray.count, by: groupSize).map {
  reversedArray[$0 ..< min($0 + groupSize, reversedArray.count)].reversed()
}.reduce([Int](), +)
print(result) //  [4, 5, 6, 1, 2, 3]

答案 1 :(得分:1)

我认为你的功能没问题,不确定你的意思是什么奇怪的tbh,可以分离到块或者以相反的方式添加每个元素,但逻辑是相同的,只需要考虑每种方式的性能/复杂性:< / p>

let a = [1,2,3,4,5,6,7,8,9,10,11]

extension Array {
    func reverse(group: Int) -> [Element] {
        guard group > 1 else { return self.reversed() }
        var new = [Element]()
        for i in stride(from: self.count-1, through: 0, by: -group) {
            let k = i-group+1 < 0 ? 0 : i-group+1
            for j in k...i {
                new.append(self[j])
            }
        }
        return new
    }
}

a.reverse(group: 4) //[8, 9, 10, 11, 4, 5, 6, 7, 1, 2, 3]

答案 2 :(得分: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]

我们正在使用stride(from:through:by:)以(减去)步幅的增量从array.count(包括)到0(不包括)进行迭代。 Swift.前缀是为了将其从过时的Swift 2 stride方法(will be gone in 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
  }
}

然后在Sequence上实现首先转换为数组的重载,然后转发到上面的实现:

extension Sequence {
  func groupedReversing(stride: Int) -> [Element] {
    return Array(self).groupedReversing(stride: stride)
  }
}

现在您可以调用它,例如CountableClosedRange,而无需先将其转换为数组:

let result = (1 ... 7).groupedReversing(stride: 3)
print(result) // [5, 6, 7, 2, 3, 4, 1]

答案 3 :(得分:0)

以下两个Swift 4.1代码段显示了如何实现CollectionArray扩展方法以便对其进行分块,反转它然后将其展平为新数组。

#1。使用AnyIteratorSequence joined()

extension Collection {

    func reverseFlattenChunked(by distance: Int) -> [Element] {
        precondition(distance > 0, "distance must be greater than 0")

        var index = endIndex
        let iterator = AnyIterator({ () -> SubSequence? in
            let newIndex = self.index(index, offsetBy: -distance, limitedBy: self.startIndex) ?? self.startIndex
            defer { index = newIndex }
            return index != self.startIndex ? self[newIndex ..< index] : nil
        })

        return Array(iterator.joined())
    }

}

用法:

let array = ["1", "2", "3", "4", "5", "6", "7"]
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: ["5", "6", "7", "2", "3", "4", "1"]

let array: [String] = ["1", "2", "3", "4", "5", "6"]
let newArray = array.reverseFlattenChunked(by: 2)
print(newArray) // prints: ["5", "6", "3", "4", "1", "2"]

let array: [String] = []
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: []

#2。使用stride(from:to:by:)Sequence flatMap(_:)

extension Array {

    func reverseFlattenChunked(by distance: Int) -> [Element] {
        precondition(distance > 0, "distance must be greater than 0")

        let indicesSequence = stride(from: self.endIndex, to: self.startIndex, by: -distance)
        let array = indicesSequence.flatMap({ (index) -> SubSequence in
            let advancedIndex = self.index(index, offsetBy: -distance, limitedBy: self.startIndex) ?? self.startIndex
            // let advancedIndex = index.advanced(by: -distance) <= self.startIndex ? self.startIndex : index.advanced(by: -distance) // also works
            return self[advancedIndex ..< index]
        })

        return array
    }

}

用法:

let array = ["1", "2", "3", "4", "5", "6", "7"]
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: ["5", "6", "7", "2", "3", "4", "1"]

let array: [String] = ["1", "2", "3", "4", "5", "6"]
let newArray = array.reverseFlattenChunked(by: 2)
print(newArray) // prints: ["5", "6", "3", "4", "1", "2"]

let array: [String] = []
let newArray = array.reverseFlattenChunked(by: 3)
print(newArray) // prints: []