Disclaimer: This is the most I've ever written in Swift. In other words, I barely know what I'm doing.
My gut feeling, Swift or no Swift, is the the findNextEvenFibonacci
function is a little too specific on its own. I'd probably have another function that just generates the next Fibonacci number - even or odd. Its parity is then checked when summing up.
Also, I don't know how to feel about the tuple. While it's a simple, direct solution a tuple also feels a little opaque. Given that structs are quite powerful in Swift, a fully declared struct with some functions might be better.
Here's my naïve attempt:
struct FibonacciPair {
var current: Int
var previous: Int
// using the name successor, since that's what Int
// calls its next-in-sequence function
func successor() -> FibonacciPair {
return FibonacciPair(current: current + previous, previous: current)
}
}
var generator = FibonacciPair(current: 1, previous: 1)
var sum = 0
while generator.current < 4_000_000 {
if generator.current % 2 == 0 {
sum += generator.current
}
generator = generator.successor()
}
let answer = sum
This is of course the sort of task that can be accomplished in a hundred different ways - the above is just what came to my mind first.
Aside: A few of those hundred other ways would be wholly procedurally without any functions or structs or other such contraptions - just a while
loop and some variables. But I figure the idea here is also to play around with Swift.
Perhaps it'd be reasonable to extend Int
with an isEven
function, while we're at it. It's basic enough to be of general use as a core type extension, and it'd clean up the while
loop above a little bit
extension Int {
func isEven() -> Bool {
return self % 2 == 0
}
}
An alternative approach might be a Fibonacci-number generator that takes a closure. If only a closure could break
the loop in which it's called instead of returning a bool... oh, well
func eachFibonacciNumber(iterator: (Int) -> (Bool)) {
var current = 1
var previous = 0
while iterator(current + previous) {
swap(&previous, ¤t)
current += previous
}
}
var sum = 0
eachFibonacciNumber() {
// note: I definitely should be checking $0 < limit *before*
// incrementing the sum... but it looks prettier if I don't :P
if $0.isEven() { sum += $0 }
return $0 < 4_000_000
}
let answer = sum
eachFibonacciNumber
is a terrible Ruby'esque-but-not-really name, but you get the idea.
The limit could also just be an argument of course, which would avoid the bool return:
func fibonacciNumbersUpTo(limit: UInt, iterator: (Int) -> ()) {
var current = 1
var previous = 0
while current < limit {
iterator(current)
swap(&previous, ¤t)
current += previous
}
}
var sum = 0
fibonacciNumbersUpTo(4_000_000) {
if $0.isEven() { sum += $0 }
}
That's is probably the nicest, most straightforward of the bunch, in my opinion.
In either case, though, the idea is to have a way to get the regular Fibonacci sequence, and then deciding what to do with each number, rather than using a specific "only even Fibonacci numbers" device. Of course, either of the above could be form the basis for such a device.
In any case, going through Project Euler with Swift is a nice idea - I'll probably do the same :)
swap
already built in? Quoting from the docs: "[...] you can use Swift’s existingswap
function rather than providing your own implementation." \$\endgroup\$swap
function out and it still works just fine. \$\endgroup\$