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

I made a deal with myself. I intend to complete the first fifty Euler problems by Wednesday, August 18. That sounds more like a challenge rather than a deal but that’s besides the point. I figure the only way I’m going to pull this off is if I cut some corners and not worry about little details like performance. I’ll still respect the one-minute run-time rule imposed by the folks over at the Euler site, but I’m not going to muck around with finding the smallest upper bound, try to minimize iterations of my loops or what have you. I’m just going to solve the problems and continue to learn Ruby along the way.

With that, you’ll find two solutions to Problem 38 below. As you’ll see I didn’t stick to my plan and I tried to optimize! The “optimized” code is more functional but it runs a heck of a lot slower! I could have continued down the refactoring path and really “functionalize” this solution and even optimize by reducing the number of iterations but I think I’ve spent enough time on the problem already.

For the record, it took me less than ten minutes to solve the problem the first way. Refactoring added an extra hour or so mostly because I got caught up in reading about inject versus reduce. I don’t like inject. It’s one of the Ruby key words which isn’t expressive in my opinion. That said, for some reason (likely the surfeit of examples), I thought the Ruby community encouraged the use of inject over reduce so I kept using it. I believe I misunderstood. Since reduce came into the language with Ruby 1.8.7, it seems that reduce is actually preferred. Maybe for no other reason than the fact that it better aligns Ruby with other languages likes Python and JavaScript as opposed to SmallTalk where I think injectoriginated. Now, there’s a lot of speculation going on here so please read with a grain of salt and please correct me if I’m wrong.

And, for the record, I feel the same way about the yield keyword as Ruby’s yield doesn’t do what yield does (continuation-y stuff) in other languages. Discuss.

As always, any feedback is welcome. Thanks for your time.

# Euler 38
# http://projecteuler.net/index.php?section=problems&id=38
# Take the number 192 and multiply it by each of 1, 2, and 3:
#
# 192 x 1 = 192
# 192 x 2 = 384
# 192 x 3 = 576
#
# By concatenating each product we get the 1 to 9 pandigital,
# 192384576. We will call 192384576 the concatenated product
# of 192 and (1,2,3)
#
# The same can be achieved by starting with 9 and multiplying
# by 1, 2, 3, 4, and 5, giving the pandigital, 918273645,
# which is the concatenated product of 9 and (1,2,3,4,5).
#
# What is the largest 1 to 9 pandigital 9-digit number that
# can be formed as the concatenated product of an integer
# with (1,2, ... , n) where n > 1?
timer_start = Time.now

answer = 0

(1..99999).each do |a|
  s = ""
  (1..9).each do |b|
    s += (a*b).to_s
    if s.length == 9 && s.split(//).sort.join == "123456789"
      answer = s.to_i if s.to_i > answer
    elsif s.length > 9
      break;
    end
  end
end

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

timer_start = Time.now
answer = 0

def longest_concatenated_product_up_to(a, l)
  (1..9).inject("") do |x, n|
     (x + (a * n).to_s).length <= l ? x + (a * n).to_s : x
  end
end

(1..99999).each do |a|
  s = longest_concatenated_product_up_to(a, 9)
  if s.length == 9 && s.split(//).sort.join == "123456789"
    answer = s.to_i if s.to_i > answer
  end
end

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

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>