Swift: how to execute a task n-1 times where n is the length of the array?
You have to be a little careful, as if the array is empty, this will work:
let a: [Int] = []
let range = 0..<a.count-1
// fatal error: Can't form Range with end < start
Strides doesn't have this problem (as Strideable
things should be Comparable
) so you can:
for _ in stride(from: 0, to: a.count - 1, by: 1) {
// will only execute if a.count > 2
print("blah")
}
Alternatively, if you are guarding it, you can use dropFirst
:
for _ in (a.isEmpty ? [] : dropFirst(a)) {
print("blah")
}
I would strongly advise against trying to make this look neater by creating a pseudo-for-loop that runs one less than the number of samples. This is the reason why no forEach
or repeat
. These types of loops seem good at first, but there are many bugs that arise from them (for example, return
or continue
do not work as you might expect, and it is also in its usual bad practice to use a higher order function to do external mutation, whereas regular cycle for
represents the assumption that mutation / side effects are likely).
The most convenient extension type solution would probably be an extension Array
to make a safe fall:
extension Array {
// version of dropFirst that returns empty array for both
// empty and single-element array
func safeDropFirst() -> ArraySlice<T> {
return self.isEmpty ? [] : dropFirst(self)
}
}
for _ in myArray.safeDropFirst() {
doThing()
}
source to share
Not much better, but:
for _ in 1..<myArray.count { task() }
But it will work if myArray
empty (thanks, Airspeed ).
If you need a lot for some reason, you can provide your own "loop abstraction" and take care of this problem:
func repeatArray<T>(arr: [T], @noescape f: () -> Void) {
if !arr.isEmpty {
for _ in 1..<arr.count {
f()
}
}
}
repeatArray(myArray) {
task()
}
source to share