Search code examples
rubyfixnum

Ruby: enumerator can't be coerced to Fixnum; struggling with Project Euler #5


The challenge is to find the smallest integer foo for which:

foo % 1..20 == 0

My current attempt is brute force

until foo % 1.upto(20) == 0 do
    foo++
end

This outputs the error unexpected keyword end. But if I don't put the end keyword into irb the code never runs, because the block isn't closed.

I made an empty test case to see where my error lays

until foo % 1.upto(20) == 0 do
end

This throws a new error: enumerator can't be coerced to a fixnum. I imagine this means you can't directly perform modulus upon a range and expect a neat boolean result for the whole range. But I don't know where to go from here.

My first attempts forewent brute force in favor of an attempt at something more efficient/elegant/to-the-point and were as follows:

foo = 1
1.upto(20) {|bar| foo *= bar unless foo % i == 0}

gave the wrong answer. I don't understand why, but I'm also interested in why

foo = 1
20.downto(1) {|bar| foo *= bar unless foo % i == 0}

outputs a different answer.

EDIT: I would have used for loops (I got my feet wet with programming in ActionScript) but they do not work how I expect in ruby.


Solution

  • If this were me, I'd define a function to test the condition:

    def mod_test(num)
      test = (1..20).map {|i| num % i == 0}
      test.all? # all are true
    end
    

    and then a loop to try different values:

    foo = 20
    until mod_test(foo) do
      foo += 20
    end
    

    (Thanks to Dylan for the += 20 speedup.)

    I'm sure that there's a clever way to use the knowledge of foo % 10 == 0 to also imply that foo % 5 == 0 and foo % 2 == 0, and perform only tests on prime numbers between 1 and 20, and probably even use that information to construct the number directly -- but my code ran quickly enough.