17

In more ruby way of doing project euler #2 , part of the code is

while((v = fib(i)) < 4_000_000)
  s+=v if v%2==0
  i+=1
end

Is there a way to change i += 1 into a more functional programming style construct?

The best I can think of is

Float::MAX.to_i.times do |i|
  v = fib(i)
  break unless v < 4_000_000
  s += v if v%2==0
end

because you can't call .times on a floating point number.

Community
  • 1
  • 1
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
  • What's `Float` got to do with it in the first place? It's all integers. – Daniel Fischer Feb 29 '12 at 23:07
  • 1
    http://stackoverflow.com/questions/6373343/math-infinity-in-ruby-how-do-i-iterate-over-an-infinite-sequence – Josh Lee Feb 29 '12 at 23:08
  • @DanielFischer: Because I can't find an integer equivalent of FLOAT::MAX. – Andrew Grimm Mar 01 '12 at 00:45
  • Ah, okay, I was afraid you were using floating point to calculate the Fibonacci numbers. But can't you do something like `sum . filter even . takeWhile (< 4000000) $ fibs` in ruby? Generate the infinite sequence lazily and consume what you need? – Daniel Fischer Mar 01 '12 at 00:53

3 Answers3

19

Numeric.step has default parameters of infinity (the limit) and 1 (the step size).

1.step do |i|
  #...
end

For fun, you might even want to try

1.step.size
steenslag
  • 79,051
  • 16
  • 138
  • 171
  • FWIW the above seems to work for Ruby 2.1 and 2.2 and up (I didn't try 2.0) The Ruby 1.9.3 equivalent is 1.step(Float::INFINITY, 1) {|i| ... } – Gayle Jan 29 '16 at 18:16
12

There’s a predefined (in 1.9.2) constant Float::INFINITY, so you could write

1.upto(Float::INFINITY) do |i|
  ...
end

(You could also use Enumerator and take_while, turning the problem inside out to make it look more like Haskell or Python, but take_while is greedy and builds an array.)

Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
Josh Lee
  • 171,072
  • 38
  • 269
  • 275
5

Ruby 2.5 introduced the open-ended Range:

(1..).each do |i|
  #...
end
steenslag
  • 79,051
  • 16
  • 138
  • 171