Project Euler Problem 1 – Sum of Multiples of 3 and 5
This is my first in a series of posts where I’ll be working through Project Euler Problems in Ruby. My goal is to write the code in an “object oriented” way along with unit tests.
There are a few reasons why I am doing this.
- To practice object oriented design and apply lessons from Practical Object Oriented Design in Ruby
- To practice unit testing and experiment with minitest
- To practice problem solving with algorithms
And last, but not least I’m doing it because I think it’s fun.
I will post the code on GitHub.
Here is the first Project Euler problem. I remember getting a problem very similar to this one at a job interview at one of my first coding jobs.
If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
Find the sum of all the multiples of 3 or 5 below 1000.
Here was my solution before refactoring:
require 'minitest/autorun'
class Problem1
def self.sum_of_multiples_of_3_and_5 num
sum = 0
(1..num-1).each do |i|
if i%5 == 0 || i%3 == 0
sum += i
end
end
sum
end
end
class Problem1Test < MiniTest::Unit::TestCase
def test_sum_of_multiples_of_3_and_5
result = Problem1.sum_of_multiples_of_3_and_5 10
assert_equal 23, result
end
end
I built a simple test case based on the example in the question. Then I wrote the class along with the class method to run the calculation. We iterate through each number from 1 up to one below the number passed in to the method. We add it to the sum if it is a multiple of 5 or 3. We can test that with the modulus operator. Then we return the sum.
At this point, we're able to get the right answer using this class. While the code works, it is limited to only multiples of 3 and 5. Let's refactor the test so we can pass in any two numbers into an Problem Solver instance.
Here is my solution after refactoring:
require 'minitest/autorun'
class Problem1
attr_accessor :first, :second
def initialize first, second
@first = first
@second = second
end
def solve num
sum = 0
(1..num-1).each do |i|
if i % @first == 0 || i % @second == 0
sum += i
end
end
sum
end
end
class Problem1Test < MiniTest::Unit::TestCase
def test_sum_of_multiples_of_3_and_5
solver = Problem1.new 3, 5
answer = solver.solve 10
assert_equal 23, answer
end
def test_sum_of_multiples_of_2_and_4
solver = Problem1.new 2, 4
answer = solver.solve 10
assert_equal 20, answer
end
end
Now we can instantiate a Problem1 object with two parameters. There is a way to pass in any number of parameters using the ruby splat * or simply passing in an array, but I'll leave that up as an exercise for the reader.
Thanks for reading.