In my attempt to learn Ruby out in the open, here’s my solution for Project Euler Problem 20.

I read through this problem and problem 19 yesterday morning before starting off on a family trip from San Diego into the woods of Northern California. With a 19 month old climbing all over me for nearly the entire duration of the two short flights, I worked through the problems in my head and jotted down the solutions on our layover at SFO. There’s nothing mind-blowing going on in either solution, but I’m very pleased that I was able to work through both solutions on paper without having to lean on Google for help with correct Ruby syntax. If you read through my solution for problem 19 you will see that I took some liberties with a switch statement which one would/could never attempt with a language like C# and everything just worked. That’s cool.

The bummer is I misunderstood problem 20 and thought through the wrong solution while on the plane. It’s a subtle difference, but I remembered the problem asking for the sum of all factorial factors, if you will, for 100!. I left that solution commented out below along with the real solution. Don’t be distracted by the useless code please, but I had to keep it in place for memories sake. Someday I’m sure my now 19 month old and I will look back at this family vacation and we’ll talk of Ruby and how it can solve all types of problem — real or fake.

As always, any feedback is welcome.

# Euler 20
# http://projecteuler.net/index.php?section=problems&id=20
# n! means n x (n - 1) x ... x 3 x 2 x 1
# Find the sum of digits in 100!
timer_start = Time.now

class Integer
  # Get the sum of all factorial values up to n
  def sum_of_factorials
    f, sum = 0, 0

    1.upto(self) { |n|
      f += n # factorial value of n
      sum += f # sum of factorial values up to n
      #puts "#{(n)} #{(f)} #{(sum)}"
      # 1 1 1
      # 2 3 4
      # 3 6 10
      # 4 10 20
      # 5 15 35
      # ...
      # 100 5050 171700
    }

    sum
  end

  def factorial
    (1..self).reduce(1, :*)
  end
end

# puts 100.sum_of_factorials

# Correct interpretation of problem.
# Get 100! and get sum of digits
numbers = 100.factorial.to_s.split(//) \
  .map(&:to_i)

puts numbers.inject(:+)

puts "Elapsed Time: #{(Time.now - timer_start)*1000} milliseconds"

Final note: Thanks to Jan Lelis for the valuable feedback on the map() and inject() argument syntax which is featured above and the suggestion to incorporate lambas into my solutions. Jan’s blog is a wealth of Ruby information (including alternate Euler Problem solutions.) If you have been keeping up with my posts, you should check out Jan’s as well — if you aren’t already.

5 Comments to “Project Euler 20: Ruby”

  1. Jon Bristow says:

    Alternatively, your code can be smooshed into

    puts (1..100).reduce(:*).to_s.split(//).inject(0) {|a,c| a + c.to_i}
  2. Ben Griswold says:

    At first I thought you were just rearranging my code and replacing the factorial method with an inline reduce. But now I see that you’re letting inject() handle the “mapping” to int and aggregation. Thanks again for feedback.

  3. J-_-L says:

    Hi Ben,

    instead of the split('') you could also use the nicer looking chars-Enumerator.

    Furthermore, you don’t need to apply the 1 to .reduce, since 1 is already the starting value of the Range.

  4. J-_-L says:

    Oh, and of course, thank you for mentioning :)

  5. Ben Griswold says:

    Good tips, Jan. Thanks and you’re welcome. :)

Leave a Reply

You can wrap your code with [ruby][/ruby] or [python][/python] blocks for syntax highlighting and you can use these traditional tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>