I think this would be a useful compliment to split, since it's quite tricky to do by hand and feels pretty common. I'm pretty skeptical of the overlapping feature though. I think that's probably overgeneralizing.
Note, it doesn't need to return an Array eagerly. This feature falls under the rule of thumb followed by the std lib that things should be lazy if there isn't a major downside to them being lazy, since it doesn't take closure. It also doesn't need to be restricted to random-access collections.
Here's a sketch of a lazy version:
struct ChunkedCollection<Base: Collection> {
let base: Base
let size: Int
}
extension ChunkedCollection: Collection {
typealias Index = Base.Index
typealias Element = Base.SubSequence
var startIndex: Base.Index { return base.startIndex }
var endIndex: Base.Index { return base.endIndex }
subscript(i: Index) -> Element { return base[i..<index(after: i)] }
func index(after i: Base.Index) -> Base.Index {
return base.index(i, offsetBy: size, limitedBy: base.endIndex) ?? base.endIndex
}
}
extension Collection {
func chunked(into size: Int) -> ChunkedCollection<Self> {
return ChunkedCollection(base: self, size: size)
}
}
let s = "abracadabra"
print(s.chunked(into: 4).joined(separator: ","))
// abra,cada,bra
This would need more work to make it into the std lib (needs preconditions, might be more efficient to have a custom index type that stashed the chunk end as well) but not too much.