I have done #1 of Project Euler's in Ruby. Using two different approaches. One uses set, another uses reduce.
require 'set'
start = Time.now
s1 = Set.new (1..1000/3.floor).map { |x| 3 * x }
s2 = Set.new (1..1000/5.floor).map { |x| 5 * x }
sum = s1.merge(s2).to_a.inject(:+)
duration = Time.now - start
puts "Sum: #{sum}, time elapsed #{duration} s"
Second method
start = Time.now
sum = (1..1000).select{ |x| x % 3 == 0 || x % 5 == 0 }.reduce(:+)
duration = Time.now - start
The second method consistently performs better than first method:
method 1: time elapsed 0.000364 s
method 2: time elapsed 0.000198 s
I wonder if it is a correct way to time how long the process takes. And whether it is considered to be performant. Also curious how other languages performs compares to this two algo. Any advice are welcomed~
2 Answers 2
Performing benchmarks with such small values is pretty much meaningless, you will usually be concerned with larger values. And this is how you tipically compare the time performance of different snippets:
require 'benchmark'
require 'set'
n = 1_000_000
Benchmark.bm do |b|
b.report("sets") do
s1 = Set.new (1..n/3.floor).map { |x| 3 * x }
s2 = Set.new (1..n/5.floor).map { |x| 5 * x }
sum = s1.merge(s2).inject(0, :+)
end
b.report("select") do
sum = (1..n).select { |x| x % 3 == 0 || x % 5 == 0 }.reduce(0, :+)
end
end
Output:
user system total real
sets 0.550000 0.020000 0.570000 ( 0.580492)
select 0.200000 0.000000 0.200000 ( 0.207238)
Code duplication:
s1 = Set.new (1..n/3.floor).map { |x| 3 * x }
s2 = Set.new (1..n/5.floor).map { |x| 5 * x }
The 2 lines above are pretty similar aren't them? What if you want to add 100 more divisors? Will you write 100 more lines? I suggest using some functions:
def divisible_by_up_to(divisor, limit)
Set.new (1..limit/divisor.floor).map { |x| divisor * x}
end
def divisible_by_all_up_to(divisors_list, limit)
# This is pseudo-code
set.merge_all([divisible_by_up_to(limit, divisor)
for divisors in divisors_list])
end
Your code than becomes more easily exapandable, modular and readable
sum = divisible_by_all_up_to([3,5], 1000).to_a.inject(:+)
Explore related questions
See similar questions with these tags.
.zero?
, sox % 3 == 0
becomes(x % 3).zero?
, and same with the second check. \$\endgroup\$