Elegant way to split an array in swift

Just for fun a generic implementation that would work with strings as well:

extension Collection {
    func every(n: Int, start: Int = 0) -> UnfoldSequence<Element,Index> {
        sequence(state: dropFirst(start).startIndex) { index in
            guard index < endIndex else { return nil }
            defer { index = self.index(index, offsetBy: n, limitedBy: endIndex) ?? endIndex }
            return self[index]
        }
    }
}

extension RangeReplaceableCollection {
    func splitIn(subSequences n: Int) -> [SubSequence] {
        (0..<n).map { .init(every(n: n, start: $0)) }
    }
}

[0, 1, 2, 3, 4, 5, 6].splitIn(subSequences: 3)   // [[0, 3, 6], [1, 4], [2, 5]]
[0, 1, 2].splitIn(subSequences: 4)               // [[0], [1], [2], []]
"0123456".splitIn(subSequences: 3)               // ["036", "14", "25"]

You can replace both loops with a map() operation:

extension Array {
    func splitInSubArrays(into size: Int) -> [[Element]] {
        return (0..<size).map {
            stride(from: $0, to: count, by: size).map { self[$0] }
        }
    }
}

The outer map() maps each offset to the corresponding array, and the inner map() maps the indices to the array elements.

Examples:

print([0, 1, 2, 3, 4, 5, 6].splitInSubArrays(into: 3))
// [[0, 3, 6], [1, 4], [2, 5]]

print([0, 1, 2].splitInSubArrays(into: 4))
// [[0], [1], [2], []]

Tags:

Arrays

Swift