交互式爱情
在Swift 3/4中,其外观如下所示:let numbers = ["1","2","3","4","5","6","7"]let chunkSize = 2let chunks = stride(from: 0, to: numbers.count, by: chunkSize).map { Array(numbers[$0..<min($0 + chunkSize, numbers.count)])}// prints as [["1", "2"], ["3", "4"], ["5", "6"], ["7"]]作为Array的扩展:extension Array { func chunked(by chunkSize: Int) -> [[Element]] { return stride(from: 0, to: self.count, by: chunkSize).map { Array(self[$0..<Swift.min($0 + chunkSize, self.count)]) } }}或者稍微冗长一些,但更笼统:let numbers = ["1","2","3","4","5","6","7"]let chunkSize = 2let chunks: [[String]] = stride(from: 0, to: numbers.count, by: chunkSize).map { let end = numbers.endIndex let chunkEnd = numbers.index($0, offsetBy: chunkSize, limitedBy: end) ?? end return Array(numbers[$0..<chunkEnd])}这是更一般的,因为我对集合中索引的类型做出的假设较少。在以前的实现中,我假设可以对它们进行比较和添加。请注意,在Swift 3中,高级索引的功能已从索引本身转移到集合中。
慕码人2483693
使用Swift 5,您可以根据需要选择以下五种方法之一来解决问题。1. AnyIterator在Collection扩展方法中使用AnyIterator是迭代符合Collection协议的对象索引以返回该对象的子序列的一个不错的选择。在Collection协议扩展中,可以chunked(by:)使用以下实现声明方法:extension Collection { func chunked(by distance: Int) -> [[Element]] { precondition(distance > 0, "distance must be greater than 0") // prevents infinite loop var index = startIndex let iterator: AnyIterator<Array<Element>> = AnyIterator({ let newIndex = self.index(index, offsetBy: distance, limitedBy: self.endIndex) ?? self.endIndex defer { index = newIndex } let range = index ..< newIndex return index != self.endIndex ? Array(self[range]) : nil }) return Array(iterator) }}用法:let array = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]let newArray = array.chunked(by: 2)print(newArray) // prints: [["1", "2"], ["3", "4"], ["5", "6"], ["7", "8"], ["9"]]2. stride(from:to:by:)在Array扩展方法中使用功能Array索引的类型Int并符合Strideable协议。因此,您可以stride(from:to:by:)与和advanced(by:)一起使用。在Array扩展中,您可以chunked(by:)使用以下实现声明方法:extension Array { func chunked(by distance: Int) -> [[Element]] { let indicesSequence = stride(from: startIndex, to: endIndex, by: distance) let array: [[Element]] = indicesSequence.map { let newIndex = $0.advanced(by: distance) > endIndex ? endIndex : $0.advanced(by: distance) //let newIndex = self.index($0, offsetBy: distance, limitedBy: self.endIndex) ?? self.endIndex // also works return Array(self[$0 ..< newIndex]) } return array }}用法:let array = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]let newArray = array.chunked(by: 2)print(newArray) // prints: [["1", "2"], ["3", "4"], ["5", "6"], ["7", "8"], ["9"]]3.在Array扩展方法中使用递归方法基于Nate Cook 递归代码,您可以使用以下实现chunked(by:)在Array扩展中声明一个方法:extension Array { func chunked(by distance: Int) -> [[Element]] { precondition(distance > 0, "distance must be greater than 0") // prevents infinite loop if self.count <= distance { return [self] } else { let head = [Array(self[0 ..< distance])] let tail = Array(self[distance ..< self.count]) return head + tail.chunked(by: distance) } }}用法:let array = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]let newArray = array.chunked(by: 2)print(newArray) // prints: [["1", "2"], ["3", "4"], ["5", "6"], ["7", "8"], ["9"]]4.在Collection扩展方法中使用for循环和批处理克里斯·艾德霍夫(Chris Eidhof)和弗洛里安·库格勒(Florian Kugler)在Swift Talk#33-Sequence&Iterator(Collections#2)视频中展示了如何使用简单的for循环填充一批序列元素,并在完成时将它们附加到数组中。在Sequence扩展中,您可以chunked(by:)使用以下实现声明方法:extension Collection { func chunked(by distance: Int) -> [[Element]] { var result: [[Element]] = [] var batch: [Element] = [] for element in self { batch.append(element) if batch.count == distance { result.append(batch) batch = [] } } if !batch.isEmpty { result.append(batch) } return result }}用法:let array = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]let newArray = array.chunked(by: 2)print(newArray) // prints: [["1", "2"], ["3", "4"], ["5", "6"], ["7", "8"], ["9"]]5.使用struct符合Sequence和IteratorProtocol协议的习惯如果你不希望创建的扩展Sequence,Collection或者Array,你可以创建自定义struct符合Sequence和IteratorProtocol协议。这struct应该具有以下实现:struct BatchSequence<T>: Sequence, IteratorProtocol { private let array: [T] private let distance: Int private var index = 0 init(array: [T], distance: Int) { precondition(distance > 0, "distance must be greater than 0") // prevents infinite loop self.array = array self.distance = distance } mutating func next() -> [T]? { guard index < array.endIndex else { return nil } let newIndex = index.advanced(by: distance) > array.endIndex ? array.endIndex : index.advanced(by: distance) defer { index = newIndex } return Array(array[index ..< newIndex]) }}用法:let array = ["1", "2", "3", "4", "5", "6", "7", "8", "9"]let batchSequence = BatchSequence(array: array, distance: 2)let newArray = Array(batchSequence)print(newArray) // prints: [["1", "2"], ["3", "4"], ["5", "6"], ["7", "8"], ["9"]]