If you want an array of subslices, you can use the split
function to generate it using a closure that captures a state variable and increments it as it passes over each element, splitting only on every nth element. As an extension of Sliceable
(Swift 2.0 only, would need to be a free function in 1.2):
extension Sliceable {
func splitEvery(n: Index.Distance) -> [SubSlice] {
var i: Index.Distance = 0
return split(self) { _ in ++i % n == 0 }
}
}
Subslices are very efficient in so much as they usually share internal storage with the original sliceable entity. So no new memory will be allocated for storing the elements - only memory for tracking the subslices' pointers into the original array.
Note, this will work on anything sliceable, like strings:
"Hello, I must be going"
.characters
.splitEvery(3)
.map(String.init)
returns ["He", "lo", " I", "mu", "t ", "e ", "oi", "g"]
.
If you want to lazily split the array up (i.e. generate a sequence that only serves up subslices on demand) you could write it using anyGenerator
:
extension Sliceable {
func lazilySplitEvery(n: Index.Distance) -> AnySequence<SubSlice> {
return AnySequence { () -> AnyGenerator<SubSlice> in
var i: Index = self.startIndex
return anyGenerator {
guard i != self.endIndex else { return nil }
let j = advance(i, n, self.endIndex)
let r = i..<j
i = j
return self[r]
}
}
}
}
for x in [1,2,3,4,5,6,7].lazilySplitEvery(3) {
print(x)
}
// prints [1, 2, 3]
// [4, 5, 6]
// [7]
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…