Swift: what is the right way to split up a [String] resulting in a [[String]] with a given subarray size?

In Swift 3/4 this would look like the following:

let numbers = ["1","2","3","4","5","6","7"]
let chunkSize = 2
let 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"]]

As an extension to 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)])
        }
    }
}

Or the slightly more verbose, yet more general:

let numbers = ["1","2","3","4","5","6","7"]
let chunkSize = 2
let 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])
}

This is more general because I am making fewer assumptions about the type of the index into the collection. In the previous implementation I assumed that they could be could be compared and added.

Note that in Swift 3 the functionality of advancing indices has been transferred from the indices themselves to the collection.

Leave a Comment