More ruby-like solution to this problem? - ruby

I am learning ruby and practicing it by solving problems from Project Euler.
This is my solution for problem 12.
# Project Euler problem: 12
# What is the value of the first triangle number to have over five hundred divisors?
require 'prime'
triangle_number = ->(num){ (num *(num + 1)) / 2 }
factor_count = ->(num) do
prime_fac = Prime.prime_division(num)
exponents = prime_fac.collect { |item| item.last + 1 }
fac_count = exponents.inject(:*)
end
n = 2
loop do
tn = triangle_number.(n)
if factor_count.(tn) >= 500
puts tn
break
end
n += 1
end
Any improvements that can be made to this piece of code?

As others have stated, Rubyists will use methods or blocks way more than lambdas.
Ruby's Enumerable is a very powerful mixin, so I feel it pays here to build an enumerable in a similar way as Prime. So:
require 'prime'
class Triangular
class << self
include Enumerable
def each
sum = 0
1.upto(Float::INFINITY) do |i|
yield sum += i
end
end
end
end
This is very versatile. Just checking it works:
Triangular.first(4) # => [1, 3, 7, 10]
Good. Now you can use it to solve your problem:
def factor_count(num)
prime_fac = Prime.prime_division(num)
exponents = prime_fac.collect { |item| item.last + 1 }
exponents.inject(1, :*)
end
Triangular.find{|t| factor_count(t) >= 500} # => 76576500
Notes:
Float::INFINITY is new to 1.9.2. Either use 1.0/0, require 'backports' or do a loop if using an earlier version.
The each could be improved by first checking that a block is passed; you'll often see things like:
def each
return to_enum __method__ unless block_given?
# ...

Rather than solve the problem in one go, looking at the individual parts of the problem might help you understand ruby a bit better.
The first part is finding out what the triangle number would be. Since this uses sequence of natural numbers, you can represent this using a range in ruby. Here's an example:
(1..10).to_a => [1,2,3,4,5,6,7,8,9,10]
An array in ruby is considered an enumerable, and ruby provides lots of ways to enumerate over data. Using this notion you can iterate over this array using the each method and pass a block that sums the numbers.
sum = 0
(1..10).each do |x|
sum += x
end
sum => 55
This can also be done using another enumerable method known as inject that will pass what is returned from the previous element to the current element. Using this, you can get the sum in one line. In this example I use 1.upto(10), which will functionally work the same as (1..10).
1.upto(10).inject(0) {|sum, x| sum + x} => 55
Stepping through this, the first time this is called, sum = 0, x = 1, so (sum + x) = 1. Then it passes this to the next element and so sum = 1, x = 2, (sum + x) = 3. Next sum = 3, x = 3, (sum + x) = 6. sum = 6, x = 4, (sum + x) = 10. Etc etc.
That's just the first step of this problem. If you want to learn the language in this way, you should approach each part of the problem and learn what is appropriate to learn for that part, rather than tackling the entire problem.
REFACTORED SOLUTION (though not efficient at all)
def factors(n)
(1..n).select{|x| n % x == 0}
end
def triangle(n)
(n * (n + 1)) / 2
end
n = 2
until factors(triangle(n)).size >= 500
puts n
n += 1
end
puts triangle(n)

It looks like you are coming from writing Ocaml, or another functional language. In Ruby, you would want to use more def to define your methods. Ruby is about staying clean. But that might also be a personal preference.
And rather than a loop do you could while (faction_count(traingle_number(n)) < 500) do but for some that might be too much for one line.

Related

Stack level too deep in recursion for largest palindrome product question (Project Euler)

I'm trying to implement a recursive solution to the largest palindrome product problem
What I'm trying to do is start both numbers at 999 and iterate down to 100 for num1 and then restart num1 at 999 and iterate num2 down by 1.
The goal is basically to mimic a nested for-loop.
def largest_palindrome_prod(num1 = 999, num2 = 999, largest_so_far = 0)
prod = num1 * num2
largest_so_far = prod if prod > largest_so_far && check_pal(prod)
if num2 == 100
return largest_so_far
elsif num1 == 100
largest_palindrome_prod(num1 = 999, num2 -= 1, largest_so_far)
else
largest_palindrome_prod(num1 -= 1, num2, largest_so_far)
end
end
#I know this function works, just here for reference
def check_pal(num)
num = num.to_s if num.is_a? Integer
if num.length < 2
true
else
num[0] == num[-1] ? check_pal(num[1..-2]) : false
end
end
rb:10:inlargest_palindrome_prod': stack level too deep`
I'm getting this error which is referring to the else statement in the largest_palindrome_prod function, but I can't figure out wast could be causing the stack error.
You don't have an infinite recursion bug. The stack is just running out of space because of the size of your input. To prove this, you can run your same function with the range of 2-digit numbers, instead of the 3-digit ones. It returns fine, which shows that there is no flaw with your logic.
How to get around this? Two options.
Option 1: You could simply not use recursion here (just use a regular nested loop instead)
Option 2: Keep your same code and enable tail call optimization:
# run_code.rb
RubyVM::InstructionSequence.compile_option = {
tailcall_optimization: true,
trace_instruction: false
}
require './palindrome_functions.rb'
puts largest_palindrome_prod
# => 906609
Note, for a reason I don't fully understand, the tail call optimization must be enabled in a different file than the code being run. So if you simply moved the compile_option line to the palindrome_functions.rb file, it wouldn't work.
I cant really give you a full explanation of tail call optimization (look it up on Wikipedia) but from my understanding, its a heavy optimization for recursive functions that only works when the recursive call is at the end of the function body. Your function meets this criteria.
#maxpleaner has answered your question and has shown how you can use recursion that avoids the stack level error. He also mentioned the option (which I expect he favours) of simply looping, rather than employing recursion. Below is one looping solution. The following method is used in the search1.
def check_ranges(range1, range2 = range1)
range1.flat_map do |n|
[n].product((range2.first..[n, range2.last].min).to_a)
end.map { |x,y| x*y }.
sort.
reverse_each.
find do |z|
arr = z.digits
arr == arr.reverse
end
end
Let's first find the largest palindrome of the product of two numbers between 960 and 999 (if there are any):
check_ranges(960..999)
#=> nil
There are none. Note that this calculation was very cheap, requiring the examination of only 40*40/2 #=> 800 products. Next, find the largest palindrome that is equal to the product of two numbers between 920 and 999.
check_ranges(920..999)
#=> 888888
Success! Note that this method re-checks the 800 products we checked earlier. It makes more sense to examine only the cases represented by the following two calls to brute_force:
check_ranges(960..999, 920..959)
#=> 888888
check_ranges(920..959)
#=> 861168
The first call computes 40*40 #=> 1600 products; the second, 800 products.
Of course, we have not yet necessarily found the largest product that is a palindrome. We do, however, have a lower bound on the largest product, which we can use to advantage. Since
888888/999
#=> 889
we infer that if the product of two numbers is larger than 888888, both of those numbers must be at least 889. We therefore need only check:
check_ranges(889..999, 889..919)
#=> 906609
check_ranges(889..919)
#=> 824428
We are finished. This tells us that 906609 is the largest product of two 3-digit numbers that is a palindrome.
The question does not ask what are the two numbers whose product is the largest palindrome, but we can easily find them:
(889..999).to_a.product((889..919).to_a).find { |x,y| x*y == 906609 }
#=> [993, 913]
993*913
#=> 906609
Moreover, let:
a = (889..999).to_a.product((889..919).to_a).map { |x,y| x*y }.
sort.
reverse
Then:
a.index { |n| n == 906609 }
#=> 84
tells us that only the largest 84 elements of this sorted group of 111*31 #=> 3441 products had to be examined before a palindrome (906609) was found.
All of this needs to be organized into a method. Though challenging for a newbie, it should be a good learning experience.
1. It would be useful to test which is faster, arr = z.digits; arr == arr.reverse or s = z.to_s; s == s.reverse.
#maxpleaner already answered, #Cary Swoveland already showed one brute force way using ranges and product. I'd like to show another brute force using a nested loop, easier to follow (IMO):
n = 9999
res = [0]
bottom = 10**(n.digits.size - 1)
n.downto(bottom) do |k|
k.downto(bottom) do |j|
# puts "#{k}, #{j}"
res = [k, j, k * j] if check_pal(k * j) && k * j > res.last
end
end
res
#=> [9999, 9901, 99000099]
I guess it can be optimized further, for example, using
n.downto(n*99/100) do |k|
k.downto(k*99/100) do |j|
Returned [99979, 99681, 9966006699] in 0.7 seconds.
Not required, but this increases the speed:
def check_pal(num)
word = num.to_s
word.reverse == word
end

Ruby - Is there a recursive solution to find the divisors of a number?

I am doing a ruby problem that wants a method to find all divisors of a number except itself with the output being a sorted array. If the number is prime, list that it is prime.
I am currently trying to teach myself recursion. Simple recursive problems like finding the factorial of a number is pretty basic to understand but I wanted to know if this particular problem could be done recursively. It seems it fits the criteria of one that could but I could not figure it out.
Example n = 15, divisors besides itself are [3,5].
My code that solved the problem.
require 'prime'
def divisors(n)
return "#{n} is prime" if Prime.prime?(n)
x = n/2
arr = []
until x == 1
arr << x if n % x == 0
x -= 1
end
arr.sort
end
Any help doing this recursively would be great or just letting me know it's not a problem that can be done this way would be helpful too.
def divisors(n, x=nil)
return "#{n} is prime" if Prime.prime?(n)
x ||= n/2
arr = []
return arr if x == 1
if n % x == 0
arr << x
end
(arr.concat divisors(n, x - 1)).sort
end
The function is refactored to handle three things:
the initial call (x ||= /2)
base cases (early returns)
iteration logic done through recursion.
An important thing is that the variable which changes during the iteration (x) is placed as a parameter for the method (with a default value, so it can essentially be used as a private parameter)
By the way, I personally found learning Elixir very helpful in understanding recursion. With pattern matching and multiple functional clauses, the initial call, base case, and iteration can be split into their own methods.

Ruby lazy enumerator returning different object types depending on use

I was attempting to solve Project Euler #58 in a functional manner with ruby.
Briefly, I created an enumerator to return the corner number of each ring. I was then chaining functional operators on the enumerator. When I get my result, I find that it has a different class depending on how I use it.
spiral = Enumerator.new do |yielder|
n = 3
step = 2
loop do
vals = n.step(nil, step).take(4)
yielder.yield vals
step += 2
n = vals.last + step
end
end
primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113]
levels = spiral
.lazy
.map { |ring| ring.count { |n| primes.include? n } }
.with_object({:total=>1.0, :primes=>0})
.take_while do |ring_primes, counts|
counts[:total] += 4
counts[:primes] += ring_primes
(counts[:primes] / counts[:total]) > 0.5
end
The class of levels is a lazy enumerator. I would expect it to contain the number of primes in each ring [3, 2, 3, etc.] - see the project euler reference.
If I just print from the enumerator, I get what I expect:
levels.each do |level|
puts "#{level}"
end
Returns:
3
2
3
1
But if I loop .with_index I get an array result back where the expected value is the first member and the second is my .with_object parameter
levels.each.with_index do |level, ix|
puts "#{ix}: #{level}"
end
Returns:
0: [3, {:total=>5.0, :primes=>3}]
1: [2, {:total=>9.0, :primes=>5}]
2: [3, {:total=>13.0, :primes=>8}]
3: [1, {:total=>17.0, :primes=>9}]
Why does the lazy enumerator work this way and how could I predict for it in the future?
Update
I asked around on the IRC ruby channel and no one there had any idea about it. They said they had discussed it a day or two ago and hadn't come to any conclusions.
In general, it seems one must just deal with it and move on.
What's happening here is you're conveniently ignoring the structure that's returned and plucking out the first item to display. In this case the first item is the counts structure you produce.
Have a look at this:
levels.each do |*level|
puts level.inspect
end
That shows you what's actually in the levels results. When Ruby calls a lambda it will discard any additional data that doesn't fit with the number of arguments the block accepts.
If you don't need that metadata, strip it out:
levels = spiral
.lazy
.map { |ring| ring.count { |n| primes.include? n } }
.with_object({:total=>1.0, :primes=>0})
.take_while do |ring_primes, counts|
counts[:total] += 4
counts[:primes] += ring_primes
(counts[:primes] / counts[:total]) > 0.5
end
.map { |r,_| r }
That removes the extraneous element in the results.
Here's a way of cleaning up your Enumerator a bit:
class Spiral
include Enumerable
def each
Enumerator.new do |yielder|
n = 3
step = 2
loop do
vals = n.step(nil, step).take(4)
yielder.yield vals
step += 2
n = vals.last + step
end
end
end
end
Then you can create one with:
Spiral.new.each ...

Using for-loop to add numbers together

If I randomly put in two numbers (first number is smaller), how do I use a for-loop to add all the numbers between and itself?
ex:
first number: 3
second number: 5
the computer should give an answer of '12'.
How do I do that using a for-loop?
In Ruby we seldom use a for loop because it leaves litter behind. Instead, you can very simply do what you want using inject:
(3..5).inject(:+) # => 12
This is using some of the deeper Ruby magic (:+), which is a symbol for the + method and is passed into inject. How it works is a different question and is something you'll need to learn later.
Don't insist on doing something in a language using a particular construct you learned in another language. That will often force non-idiomatic code and will keep you from learning how to do it as other programmers in that language would do it. That creates maintenance issues and makes you less desirable in the workplace.
Simple for loop across the range you defined:
puts "Enter first number: "
first = gets.to_i
puts "Enter second number: "
second = gets.to_i
total = 0
for i in (first..second) do
total += i
end
puts total
Note that if you don't enter a valid number, it will converted to 0. Also this assumes the second number is larger than the first.
In Rails, or in plain-vanilla Ruby with ActiveSupport, you can do something even simpler than a for loop, or than what other people wrote.
(first_num..second_num).sum
This is shorthand for sum in Ruby:
sum = 0
(first_num..second_num).each { |num| sum += num }
first, second = [3,5]
for x in (0..0) do
p (first + second)*(second - first + 1) / 2
end
I know you said for loop, but why not use what Ruby gives you?
> a = 3
> b = 5
> a.upto(b).inject(0) {|m,o| m += o}
=> 12
If you insist on a for loop...
> m = 0
=> 0
> for i in 3..5
* m += i
* end
=> 3..5
> m
=> 12
Since Ruby 2.4 you directly call sum on an Enumerable.
For Example [1, 2, 3].sum #=> 6
In Ruby it's very rare to see a for loop. In this instance a more idiomatic method would be upto:
x = 3
y = 5
total = 0
x.upto(y) do |n|
total += n
end
puts total
# => 12
Another method would be to use reduce:
total = x.upto(y).reduce do |sum, n|
sum += n
end
...which can be shortened to this:
total = x.upto(y).reduce(&:+)

Iterate over an infinite sequence in Ruby

I am trying to solve Project Euler problem #12:
The sequence of triangle numbers is generated by adding the natural
numbers. So the 7th triangle number
would be 1 + 2 + 3 + 4 + 5 + 6 + 7 =
28. The first ten terms would be:
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, ...
Let us list the factors of the first seven triangle numbers:
1: 1
3: 1,3
6: 1,2,3,6
10: 1,2,5,10
15: 1,3,5,15
21: 1,3,7,21
28: 1,2,4,7,14,28
We can see that 28 is the first triangle number to have over five
divisors.
What is the value of the first triangle number to have over five
hundred divisors?
Here's the solution that I came up with using Ruby:
triangle_number = 1
(2..9_999_999_999_999_999).each do |i|
triangle_number += i
num_divisors = 2 # 1 and the number divide the number always so we don't iterate over the entire sequence
(2..( i/2 + 1 )).each do |j|
num_divisors += 1 if i % j == 0
end
if num_divisors == 500 then
puts i
break
end
end
I shouldn't be using an arbitrary huge number like 9_999_999_999_999_999. It would be better if we had a Math.INFINITY sequence like some functional languages. How can I generate a lazy infinite sequence in Ruby?
Several answers are close but I don't actually see anyone using infinite ranges. Ruby supports them just fine.
Inf = Float::INFINITY # Ruby 1.9
Inf = 1.0/0 # Ruby before 1.9
(1..Inf).include?(2305843009213693951)
# => true
(1..Inf).step(7).take(3).inject(&:+)
# => 24.0
In your case
(2..Inf).find {|i| ((2..( i/2 + 1 )).select{|j| i % j == 0}.count+2)==42 }
=> 2880
Your brute force method is crude and can, potentially, take a very long time to finish.
In Ruby >= 1.9, you can create an Enumerator object that yields whatever sequence you like. Here's one that yields an infinite sequence of integers:
#!/usr/bin/ruby1.9
sequence = Enumerator.new do |yielder|
number = 0
loop do
number += 1
yielder.yield number
end
end
5.times do
puts sequence.next
end
# => 1
# => 2
# => 3
# => 4
# => 5
Or:
sequence.each do |i|
puts i
break if i >= 5
end
Or:
sequence.take(5).each { |i| puts i }
Programming Ruby 1.9 (aka "The Pickaxe Book"), 3rd. ed., p. 83, has an example of an Enumerator for triangular numbers. It should be easy to modify the Enumerator above to generate triangular numbers. I'd do it here, but that would reproduce the example verbatim, probably more than "fair use" allows.
Infinity is defined on Float (Ruby 1.9)
a = Float::INFINITY
puts a #=> Infinity
b = -a
puts a*b #=> -Infinity, just toying
1.upto(a) {|x| break if x >10; puts x}
Currrent versions of Ruby support generators heavily:
sequence = 1.step
In Ruby 2.6 this becomes much easier:
(1..).each {|n| ... }
Source: https://bugs.ruby-lang.org/issues/12912
This would be best as a simple loop.
triangle_number = 1
i = 1
while num_divisors < 500
i += 1
triangle_number += i
# ...
end
puts i
As Amadan mentioned you can use closures:
triangle = lambda { t = 0; n = 1; lambda{ t += n; n += 1; t } }[]
10.times { puts triangle[] }
Don't really think it is much slower than a loop. You can save state in class object too, but you will need more typing:
class Tri
def initialize
#t = 0
#n = 1
end
def next
#t += n
#n += 1
#t
end
end
t = Tri.new
10.times{ puts t.next }
Added:
For those who like longjmps:
require "generator"
tri =
Generator.new do |g|
t, n = 0, 1
loop do
t += n
n += 1
g.yield t
end
end
puts (0..19).map{ tri.next }.inspect
Building on Wayne's excellent answer and in the Ruby spirit of doing things with the least number of characters here is a slightly updated version:
sequence = Enumerator.new { |yielder| 1.step { |num| yielder.yield num } }
Obviously, doesn't solve the original Euler problem but is good for generating an infinite sequence of integers. Definitely works for Ruby > 2.0. Enjoy!
On Christmas Day 2018, Ruby introduced the endless range, providing a simple new approach to this problem.
This is implemented by ommitting the final character from the range, for example:
(1..)
(1...)
(10..)
(Time.now..)
Or to update using Jonas Elfström's solution:
(2..).find { |i| ((2..( i / 2 + 1 )).select { |j| i % j == 0 }.count + 2) == 42 }
Hope this proves useful to someone!
I believe that fibers (added in Ruby 1.9 I believe) may be close to what you want. See here for some information or just search for Ruby Fibers

Resources