patternswiftMinor
Swift replacement for C's for-loop
Viewed 0 times
swiftloopforreplacement
Problem
I recently wrote an entry on my blog regarding unit testing using prime numbers as an example.
When I wrote the entry, I wrote my code keeping in minding that proposal SE-0007 has been accepted for Swift 3.0. That is, C-style for loops will no longer be available in Swift as of 3.0, so I want to completely discontinue using them.
That is to say, where I might have written something like this:
I was instead stuck with some real ugliness in my prime loop.
I am satisfied that this code works as I want. I am also satisfied that is runs extraordinarily fast.
What I do not like about this is the very round-about way I have to achieve the same behavior a C-style
But this doesn't allow for the same early stopping point:
And making the first line of the loop check this isn't much better:
```
for divisor in 7.stride(through: value, by: 30) {
if divisor * divi
When I wrote the entry, I wrote my code keeping in minding that proposal SE-0007 has been accepted for Swift 3.0. That is, C-style for loops will no longer be available in Swift as of 3.0, so I want to completely discontinue using them.
That is to say, where I might have written something like this:
for(int divisor = 7; divisor * divisor <= value; divisor += 30) {I was instead stuck with some real ugliness in my prime loop.
func isPrime(value: Int) -> Bool {
if value < 2 { return false }
if value % 2 == 0 { return value == 2 }
if value % 3 == 0 { return value == 3 }
if value % 5 == 0 { return value == 5 }
if value == 7 { return true }
var divisor = 7
while divisor * divisor <= value {
if value % divisor == 0 { return false }
if value % (divisor + 4) == 0 { return false }
if value % (divisor + 6) == 0 { return false }
if value % (divisor + 10) == 0 { return false }
if value % (divisor + 12) == 0 { return false }
if value % (divisor + 16) == 0 { return false }
if value % (divisor + 22) == 0 { return false }
if value % (divisor + 24) == 0 { return false }
divisor += 30
}
return true
}I am satisfied that this code works as I want. I am also satisfied that is runs extraordinarily fast.
What I do not like about this is the very round-about way I have to achieve the same behavior a C-style
for loop would have given me. In particular, it is the termination point that concerns me. I could easily get the same loop steps with the stride function:for divisor in 7.stride(through: value, by: 30) {But this doesn't allow for the same early stopping point:
divisor * divisior <= valueAnd making the first line of the loop check this isn't much better:
```
for divisor in 7.stride(through: value, by: 30) {
if divisor * divi
Solution
Python also has no C-style for-loop. A lot of Python novices write clumsy while-loops as a result. However, once you learn the Pythonic idioms for looping, you'll wonder why other languages aren't more like Python.
The trick is to get to know…
If I had to translate your Swift code to Python, I would do it using
Kevin Ballard has posted a proposal on the swift-evolution mailing list to introduce a
The trick is to get to know…
- the
range()built-in function, which looks a lot like thestride(through: by:)that you suggested
- the
enumerate()built-in function, for when you need to iterate over a list and also increment a counter at the same time
- the
itertoolslibrary for more complex situations
If I had to translate your Swift code to Python, I would do it using
itertools.count() to generate the infinite sequence [7, 37, 67, 97, …], and itertools.takewhile() to terminate it.from itertools import count, takewhile
def is_prime(value):
if value < 2: return False
if value % 2 == 0: return value == 2
if value % 3 == 0: return value == 3
if value % 5 == 0: return value == 5
if value == 7: return True
for divisor in takewhile(lambda d: d * d <= value, count(7, 30)):
if value % divisor == 0: return False
for offset in [4, 6, 10, 12, 16, 22, 24]:
if value % (divisor + offset) == 0: return False
return TrueKevin Ballard has posted a proposal on the swift-evolution mailing list to introduce a
takeWhile() to the standard library. I think that a rich library for manipulating sequence types would make a good replacement for C-style for-loops.Code Snippets
from itertools import count, takewhile
def is_prime(value):
if value < 2: return False
if value % 2 == 0: return value == 2
if value % 3 == 0: return value == 3
if value % 5 == 0: return value == 5
if value == 7: return True
for divisor in takewhile(lambda d: d * d <= value, count(7, 30)):
if value % divisor == 0: return False
for offset in [4, 6, 10, 12, 16, 22, 24]:
if value % (divisor + offset) == 0: return False
return TrueContext
StackExchange Code Review Q#118445, answer score: 6
Revisions (0)
No revisions yet.