if $0 == __FILE__
total = 0
def fibonacci_below max
first = 1
second = 2
fib = [first, second]
while second+first <= max
fib << first + second
first = second
second = fib.last
end
fib
end
fib = fibonacci_below(4000000)
fib.reject!{ |x| x.odd?}
p fib.inject{|sum, x| sum + x}
end
Refactorings
No refactoring yet !
Ants
January 24, 2012, January 24, 2012 20:20, permalink
Your code is already nicely written with loose coupling and tight cohesion. For general purpose code, or code that will be maintained over a long time, you want to keep things this way. You've nicely separated the concerns, and made the code very readable as to what is happening through its phases of operation.
Unfortunately, for the Euler project problems. Often the general purpose solutions are the slowest. Code has to be written precisely to solve that problem, and quite often that problem only. By taking advantage of the characteristics of the problem, one gets insights and can optimize the algorithm/code. So one can then refactor the code to be optimal, but not always necessarily more readable. (Personally, for code that I'll be expected to maintain over the long run, I'll always pick readable over fast, but that's just my preference.)
So to that end of refactoring to go faster, notice how your code loops over the array multiple times. The first time is to actually generate the contents. The second to reject the odd numbers, and the last to sum up the numbers. Since all that matters is just getting the sum at the end of the run, you can forego of maintaining the array, and just keeping a running sum of all the odd numbers.
def sum_odd_fib_numbers_below max
first = 1
second = 2
fib = first + second
sum = 1
while fib <= max
sum += fib if fib.odd?
first = second
second = fib
fib = first + second
end
sum
end
print sum_odd_fib_numbers_below 4000000
Ants
January 24, 2012, January 24, 2012 20:30, permalink
Sorry, the point was to get the sum of all the even Fibonacci numbers...
def sum_even_fib_numbers_below max
return 0 if max < 2
first = 1
second = 2
fib = first + second
sum = 2
while fib <= max
sum += fib if fib.even?
first = second
second = fib
fib = first + second
end
sum
end
print sum_even_fib_numbers_below 4000000
Ants
January 24, 2012, January 24, 2012 20:46, permalink
And getting rid of the ugly corner case check for max < 2, and using the multi-assignment...
def sum_even_fib_numbers_below max
prev = 1
fib = 1
sum = 0
while fib <= max
sum += fib if fib.even?
prev, fib = fib, prev + fib
end
sum
end
print sum_even_fib_numbers_below 4000000
Sorry if I shouldn't be posting these solutions here... I'm learning Ruby and know there has to be some better ways to do this...