I have large list of objects and I need to split them in a group of two elements for UI propouse.
Example:
[0, 1, 2, 3, 4, 5, 6]
Becomes an array with these four arrays
[[0, 1], [2, 3], [4, 5], [6]]
There are a ton of ways to split an array. But, what is the most efficient (least costly) if the array is huge.
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]
The shortest solution (Swift 4), I have seen so far, is from a Gist:
extension Array {
func chunks(chunkSize: Int) -> [[Element]] {
return stride(from: 0, to: self.count, by: chunkSize).map {
Array(self[$0..<Swift.min($0 + chunkSize, self.count)])
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With