Hi there! I’m trying to write some code that splits collections into subsequences based on chunks. An array of integers and a chunk size of 2, for instance, transforms from [1, 2, 3, 4, 5, 6]
to [[1, 2], [3, 4], [5, 6]]
. I can achieve this nicely using the following code:
extension Collection {
public func chunked(into size: Int) -> [SubSequence] {
var chunks: [SubSequence] = []
var i = startIndex
while let nextIndex = index(i, offsetBy: size, limitedBy: endIndex) {
let chunk = self[i ..< nextIndex]
chunks.append(chunk)
i = nextIndex
}
let finalChunk = self[i ..< endIndex]
if finalChunk.isEmpty == false {
chunks.append(finalChunk)
}
return chunks
}
}
But I feel like that could be better. I can rewrite it a bit so that it works on any Collection
where the Index
is an Int
:
extension Collection where Index == Int {
public func chunked(into size: Index.Stride) -> [SubSequence] {
return stride(from: startIndex, to: endIndex, by: size).map { index in
let end = self.index(index, offsetBy: size, limitedBy: self.endIndex) ?? endIndex
return self[index ..< end]
}
}
}
But that means that I can’t use it with String
, so I need to have another extension:
extension StringProtocol {
public func chunked(into size: Int) -> [SubSequence] {
var chunks: [SubSequence] = []
var i = startIndex
while let nextIndex = index(i, offsetBy: size, limitedBy: endIndex) {
chunks.append(self[i ..< nextIndex])
i = nextIndex
}
let finalChunk = self[i ..< endIndex]
if finalChunk.isEmpty == false {
chunks.append(finalChunk)
}
return chunks
}
}
Is there a more concise way to achieve the desired result in Swift 5.1 without having separate code paths for String
and other Collection
s?