I am writing Pascal's triangle in Ruby, but keep getting the error message:
pascalsTriangle.rb:3:in 'triangle': undefined method `each' for
4:Fixnum (NoMethodError) from pascalsTriangle.rb:18
def triangle(n)
for r in n:
lst=[1]
term=1
k=0
(0..r+1).step(1){ |index|
term=term*(r-k+1)/k
lst.append(term)
k+=1
}
print lst
end
end
triangle(4)
Why code C style in Ruby? :-)
Breaking the problem down would allow you to concentrate on one problem at a time and iterators would make the code more readable. I'm using the binomial theorem to calculate the values in the triangle. If you don't need a super large value from the triangle, this will be fast enough.
Calculating the 1000th line took 2.9 seconds on my virtual linux:
# factorial method
def fact(n)
(1..n).reduce(:*)
end
# binomial theorem, n choose k
def binomial(n,k)
return 1 if n-k <= 0
return 1 if k <= 0
fact(n) / ( fact(k) * fact( n - k ) )
end
def triangle(nth_line)
(0..nth_line).map { |e| binomial(nth_line, e) }
end
p triangle(5)
the final source code:
def triangle(n)
(0..n).each{|r|
lst=[1]
term=1
k=1
(0..r-1).step(1){|index|
term=term*(r-k+1)/k
lst.push term
k+=1
}
p lst
}
end
triangle(4)
changes:
you have syntax error on for r in n:.
a logical error on k=0 that causes Division by zero.
(0..r+1) is changed to (0..r-1)
there is no append method for array. changed to push
p is used instead of print
Factorial(num), takes a number and return the factorial of it.
find_num(n, k), is the mathmatical formula of pascales triangle. !n/
!k * !(n - k) ---- '!' = factorial of number
Lastly pascale(num), this iterates a new row of the triangle by
maping the index numbers or (k) for each row of (n).
If you want to truly understand how this works comment out the
pascale, and simply run numbers through find_num((row number),
(index number)). Then compare to a picture of the triangle to see
the magic for your self
-
def find_num(n, k)
result = factorial(n) / (factorial(k) * factorial(n - k))
end
def pascale(num)
i = 0
scale = 75
while i <= num
new_arr = []
(0..i).map {|x| new_arr << find_num(i, x)}
p new_arr.to_s.rjust(50 + scale)
i += 1
scale += 1
end
def factorial(num)
if num == 0
return 1
else
num *= factorial(num - 1)
end
end
end
pascale(12)
Related
I have solved a Codewars kata, but I can not submit it because my code takes too long. A lot of people had this problem, but we can not see the solution. The problem is, that generating the prime numbers takes too long (more than 12s) (I generate the primes with a method).
In my computer, I can require the class Prime, and this solves the problem. But in Codewar one can not require the class Prime, therefore, my method of generating prime numbers is too slow.
Any help?
require "pry"
def primeFactors(n)
start_time = Time.now
puts start_time
# find prime numbers smaller than n
nums = (2..(n-1)).to_a
odd_nums = nums.select { |num| num.odd? }
primes = odd_nums.select do |num|
is_prime(num)
end
end_time = Time.now
duration = end_time - start_time
puts end_time
# divide until mod is 1
dividend = n
res_primes = []
while dividend > 1
primes.each do |prime| # prime divisor
new_dividend = dividend.to_f / prime
remainder = dividend % prime
if remainder.zero?
dividend = new_dividend
res_primes << prime
break
end
end
end
freqs = {}
res_primes.each do |res_prime|
freqs[res_prime] = res_primes.count(res_prime)
end
res_string = []
freqs.keys.each do |key|
if freqs[key] == 1
res_string << "(#{key})"
else
res_string << "(#{key}**#{freqs[key]})"
end
end
res_string.join
end
def is_prime(n)
(2..n/2).none?{|i| n % i == 0}
end
Well for starters you really only need to test to Math.sqrt(n).to_i + 1 that should help for larger n values.
This is because if a factor exists where n = a * b then either
If a == b == sqrt(n) # Basically the defn of sqrt
or
If a != b; a < sqrt(n); b > sqrt(n)
If both a and b are less than sqrt(n) then a * b < n
and
If both a and b are greater than sqrt(n) the a * b > n
Secondly, and this is more complex, you only need to test prime numbers to that limit. I could envision a scheme where primes are cached.
Hope this helps.
The more advanced option might look like this:
# Is this number a prime?
module PrimeChecker
#prime_cache = [2,3]
def self.prime?(n)
search_limit = Math.sqrt(n).to_i + 1
last_cache = #prime_cache[-1]
while last_cache < search_limit do
last_cache += 2
#prime_cache << last_cache if PrimeChecker.prime?(last_cache)
end
#prime_cache.each do |pn|
return true if pn > search_limit
return false if (n % pn) == 0
end
true
end
end
# Sample run
#
# 31 mysh>%=PrimeChecker.prime?(1_000_000_000_000)
# false
# Elapsed execution time = 1.592 seconds.
#
This running on an elderly machine with a slow CORE 2 Duo processor.
Im learning Ruby and currently this is my exercise:
Using any pair of numbers, prove integer n is a Perfect Power. If there are no pairs, return nil.
In mathematics, a perfect power is a positive integer that can be expressed as an integer power of another positive integer. More formally, n is a perfect power if there exist natural numbers m > 1, and k > 1 such that mk = n
Currently this is my code:
def pp(n)
# [m,k] m^k
idx1=2
while idx1 <n
idx2=2
while idx2<n
if idx1**idx2 == n
ans = [idx1,idx2]
break
end
idx2 +=1
end
idx1 +=1
end
return ans
end
I would like to write this such that for a given random huge number my repl.it does not time out.
Thank you in advance!
###Edit###
There is a mention(How to make perfect power algorithm more efficient?) of this problem in the context of Python. As much as I tried to understand it and translate the syntax, I could not. I hope that asking this question will also help those studying Ruby as much as it has helped me.
You could use the prime factorization:
require 'prime'
def pp(n)
pd = n.prime_division
k = pd.map(&:last).reduce(&:gcd)
return if k < 2
m = pd.map { |p, e| p**(e / k) }.reduce(:*)
[m, k]
end
For example for n = 216 you get [[2, 3], [3, 3]], meaning 216 = 23⋅33. Then find the greatest common divisor of the exponents, which is the greatest possible exponent k. If it's less than 2, you lose. Otherwise, compute the base m from the pieces.
Yours takes my PC about 4.1 seconds to check the numbers from 2 to 200. Mine takes about 0.0005 seconds for that, and takes about 2.9 seconds to check the numbers 2 to 400000.
Wanna solve really large numbers like this instantaneously? With a much shorter solution?
pp(908485319620418693071190220095272672648773093786320077783229)
=> [29, 41]
Then read on :-). It'll be a little journey...
Let's first just make your code nicer without changing the logic at all. Just rename your variables to m and k and loop with each:
def pp1(n)
ans = nil
(2...n).each do |m|
(2...n).each do |k|
if m**k == n
ans = [m, k]
break
end
end
end
ans
end
Now checking n up to 200 takes me about 4.1 seconds (same as your original):
> require 'benchmark'
> puts Benchmark.measure { (1..200).each { |n| pp1(n) } }
4.219000 0.000000 4.219000 ( 4.210381)
First optimization: If we find a solution, return it right away!
def pp2(n)
(2...n).each do |m|
(2...n).each do |k|
if m**k == n
return [m, k]
end
end
end
nil
end
Sadly it still takes 3.9 seconds for the test. Next optimization: If mk is already too large, let's not try even larger k!
def pp3(n)
(2...n).each do |m|
(2...n).each do |k|
break if m**k > n
if m**k == n
return [m, k]
end
end
end
nil
end
Now it's so fast that I can run the test 1000 times in about the same time:
> puts Benchmark.measure { 1000.times { (1..200).each { |n| pp3(n) } } }
4.125000 0.000000 4.125000 ( 4.119359)
Let's instead go up to n = 5000:
> puts Benchmark.measure { (1..5000).each { |n| pp3(n) } }
2.547000 0.000000 2.547000 ( 2.568752)
Now instead of computing m**k so much, let's use a new variable that we can update more cheaply:
def pp4(n)
(2...n).each do |m|
mpowk = m
(2...n).each do |k|
mpowk *= m
break if mpowk > n
if mpowk == n
return [m, k]
end
end
end
nil
end
Sadly, this almost didn't make it faster at all. But there's another optimization: When mk is too large, then not only can we forget trying this m with even larger k. If it was too large for k=2, i.e., m2 is already too large, then we don't need to try even larger m, either. We can stop the whole search. Let's try that:
def pp5(n)
(2...n).each do |m|
mpowk = m
(2...n).each do |k|
mpowk *= m
if mpowk > n
return if k == 2
break
end
if mpowk == n
return [m, k]
end
end
end
nil
end
This now does the 5000-test in about 0.07 seconds! We can even check all numbers up to 100000 in 6 seconds:
> puts Benchmark.measure { (1..100000).each { |n| pp5(n) } }
5.891000 0.000000 5.891000 ( 5.927859)
Anyway, let's look at the big picture. We're trying m = 2.. and for each m we try to find a k so that m**k == n. Hey, math has a solution for that! We can compute k as k=logm(n). Let's do it:
def pp6(n)
(2...n).each do |m|
k = Math.log(n, m).round
return if k < 2
return [m, k] if m**k == n
end
nil
end
Measure again:
> puts Benchmark.measure { (1..100000).each { |n| pp6(n) } }
28.797000 0.000000 28.797000 ( 28.797254)
Hmm, slower. Ok, another idea: Let the outer loop be for k instead of m. Now for given n and k, how do we find m such that mk = n? Take the k-th root!
def pp7(n)
(2...n).each do |k|
m = (n**(1.0 / k)).round
return if m < 2
return [m, k] if m**k == n
end
nil
end
Measure again:
> puts Benchmark.measure { (1..100000).each { |n| pp7(n) } }
0.828000 0.000000 0.828000 ( 0.836402)
Nice. How about 400000, which my factorization solution in my other answer solved in 2.9 seconds?
> puts Benchmark.measure { (1..400000).each { |n| pp(n) } }
3.891000 0.000000 3.891000 ( 3.884441)
Ok that's a bit slower. But... with this solution here we can solve really large numbers:
pp7(1000000035000000490000003430000012005000016807)
=> [1000000007, 5]
pp7(908485319620418693071190220095272672648773093786320077783229)
=> [29, 41]
> pp7(57248915047290578345908234051234692340579013460954153490523457)
=> nil
And all these result appears immediately. The factorization solution solves the 2941 case quickly as well, but for the 10000000075 case and the randomly-typed case at the end it's slow, because the factorization is slow.
P.S. Note that the logarithm and square root get us floating point numbers. That could lead to problems with very large numbers. For example:
irb(main):122:0> pp7(10**308 + 1)
=> nil
irb(main):123:0> pp7(10**309 + 1)
FloatDomainError: Infinity
from (irb):82:in `round'
from (irb):82:in `block in pp7'
from (irb):81:in `each'
from (irb):81:in `pp7'
from (irb):123
from C:/Ruby24/bin/irb.cmd:19:in `<main>'
In this case, that's because 10309 simply is too large for floats:
> (10**309).to_f
=> Infinity
Also, there could be accuracy problems with large enough numbers. Anyway, you can solve these issues by writing integer-versions for logarithm and root. But that's a whole other issue.
While trying to solve the "paths on a grid" problem, I have written the code
def paths(n, k)
p = (1..n+k).to_a
p.combination(n).to_a.size
end
The code works fine, for instance if n == 8 and k == 2 the code returns 45 which is the correct number of paths.
However the code is very slow when using larger numbers and I'm struggling to figure out how to quicken the process.
Rather than building the array of combinations just to count it, just write the function that defines the number of combinations. I'm sure there are also gems that include this and many other combinatorics functions.
Note that I am using the gem Distribution for the Math.factorial method, but that is another easy one to write. Given that, though, I'd suggest taking #stefan's answer, as it's less overhead.
def n_choose_k(n, k)
Math.factorial(n) / (Math.factorial(k) * Math.factorial(n - k))
end
n_choose_k(10, 8)
# => 45
Note that the n and k here refer to slightly different things than in your method, but I am keeping them as it is highly standard nomenclature in combinatorics for this function.
def combinations(n, k)
return 1 if k == 0 or k == n
(k + 1 .. n).reduce(:*) / (1 .. n - k).reduce(:*)
end
combinations(8, 2) #=> 28
Explanation about the math part
The original equation is
combinations(n, k) = n! / k!(n - k)!
Since n! / k! = (1 * 2 * ... * n) / (1 * 2 * ... * k), for any k <= n there is a (1 * 2 * ... * k) factor both in the numerator and in the denominator, so we can cancel this factor. This makes the equation become
combinations(n, k) = (k + 1) * (k + 2) * ... * (n) / (n - k)!
which is exactly what I did in my Ruby code.
The answers that suggest computing full factorials will generate lots of unnecessary overhead when working with big numbers. You should use the method below for calculating the binomial coefficient: n!/(k!(n-k)!)
def n_choose_k(n, k)
return 0 if k > n
result = 1
1.upto(k) do |d|
result *= n
result /= d
n -= 1
end
result
end
This will perform the minimum operations needed. Note that incrementing d while decrementing n guarantees that there will be no rounding errors. For example, {n, n+1} is guaranteed to have at least one element divisible by two, {n, n+1, n+2} is guaranteed to have at least one element divisible by three and so on.
Your code can be rewritten as:
def paths(x, y)
# Choice of x or y for the second parameter is arbitrary
n_choose_k(x + y, x)
end
puts paths(8, 2) # 45
puts paths(2, 8) # 45
I assume that n and k in the original version were meant to be dimensions so i labeled them x and y instead. There's no need to generate an array here.
Edit: Here is a benchmark script...
require 'distribution'
def puts_time
$stderr.puts 'Completed in %f seconds' % (Time.now - $start_time)
$start_time = Time.now
end
def n_choose_k(n, k)
return 0 if k > n
result = 1
1.upto(k) do |d|
result *= n
result /= d
n -= 1
end
result
end
def n_choose_k_distribution(n, k)
Math.factorial(n) / (Math.factorial(k) * Math.factorial(n - k))
end
def n_choose_k_inject(n, k)
(1..n).inject(:*) / ((1..k).inject(:*) * (1..n-k).inject(:*))
end
def benchmark(&callback)
100.upto(300) do |n|
25.upto(75) do |k|
callback.call(n, k)
end
end
end
$start_time = Time.now
puts 'Distribution gem...'
benchmark { |n, k| n_choose_k_distribution(n, k) }
puts_time
puts 'Inject method...'
benchmark { |n, k| n_choose_k_inject(n, k) }
puts_time
puts 'Answer...'
benchmark { |n, k| n_choose_k(n, k) }
puts_time
Output on my system is:
Distribution gem...
Completed in 1.141804 seconds
Inject method...
Completed in 1.106018 seconds
Answer...
Completed in 0.150989 seconds
Since you're interested in the count rather than the actual combination sets, you should do this with a choose function. The mathematical definition involves evaluating three different factorials, but there's a lot of cancellation going on so you can speed it up by using ranges to avoid the calculations that will be cancelled anyway.
class Integer
def choose(k)
fail 'k > n' if k > self
fail 'args must be positive' if k < 0 or self < 1
return 1 if k == n || k == 0
mm = [self - k, k].minmax
(mm[1]+1..self).reduce(:*) / (2..mm[0]).reduce(:*)
end
end
p 8.choose 6 # => 28
To solve your paths problem, you could then define
def paths(n, k)
(n + k).choose(k)
end
p paths(8, 2) # => 45
The reduce/inject versions are nice. But since speed seemed to be a bit of an issue, I'd suggest the n_choose_k versions from #google-fail.
It is quite insightful and suggests a ~10-fold speed increase.
I would suggest that the iteration use the Lesser of k and ( n - k ).
N-choose-K and N-choose-(N-K) produce the same result (the factors in the denominator are simply reversed). So something like a 52-choose-51 could be done in one iteration.
I usually do the following:
class Integer
def !
(2..self).reduce(1, :*)
end
def choose(k)
self.! / (k.! * (self-k).!)
end
end
Benchmarking:
k = 5
Benchmark.bm do |x|
[10, 100, 1000, 10000, 100000].each do |n|
x.report("#{n}") { n.choose(k) }
end
end
On my machine I get:
user system total real
10 0.000008 0.000001 0.000009 ( 0.000006)
100 0.000027 0.000003 0.000030 ( 0.000031)
1000 0.000798 0.000094 0.000892 ( 0.000893)
10000 0.045911 0.013201 0.059112 ( 0.059260)
100000 4.885310 0.229735 5.115045 ( 5.119902)
Not the fastest thing on the planet, but it's okay for my uses. If it ever becomes a problem, then I can think about optimizing
The following is a method I wrote to calculate a value in the Fibonacci sequence:
def fib(n)
if n == 0
return 0
end
if n == 1
return 1
end
if n >= 2
return fib(n-1) + (fib(n-2))
end
end
It works uptil n = 14, but after that I get a message saying the program is taking too long to respond (I'm using repl.it). Anyone know why this is happening?
Naive fibonacci makes a lot of repeat calculations - in fib(14) fib(4) is calculated many times.
You can add memoization to your algorithm to make it a lot faster:
def fib(n, memo = {})
if n == 0 || n == 1
return n
end
memo[n] ||= fib(n-1, memo) + fib(n-2, memo)
end
fib 14
# => 377
fib 24
# => 46368
fib 124
# => 36726740705505779255899443
As others have pointed out, your implementation's run time grows exponentially in n. There are much cleaner implementations.
Constructive [O(n) run time, O(1) storage]:
def fib(n)
raise "fib not defined for negative numbers" if n < 0
new, old = 1, 0
n.times {new, old = new + old, new}
old
end
Memoized recursion [O(n) run time, O(n) storage]:
def fib_memo(n, memo)
memo[n] ||= fib_memo(n-1, memo) + fib_memo(n-2, memo)
end
def fib(n)
raise "fib not defined for negative numbers" if n < 0
fib_memo(n, [0, 1])
end
Recursive powers of a matrix multiplication using squared halving of the power for when you just gotta know really big factorials like 1_000_000.fib [O(log n) run time and storage (on stack)]:
def matrix_fib(n)
if n == 1
[0,1]
else
f = matrix_fib(n/2)
c = f[0] * f[0] + f[1] * f[1]
d = f[1] * (f[1] + 2 * f[0])
n.even? ? [c,d] : [d,c+d]
end
end
def fib(n)
raise "fib not defined for negative numbers" if n < 0
n.zero? ? n : matrix_fib(n)[1]
end
Your program has exponential runtime due to the recursion you use.
Expanding only the recursive calls a few levels to show you why:
fib(14) = fib(13) + fib(12)
= (fib(12) + fib(11)) + (fib(11) + fib (10))
= (((fib(11) + fib(10)) + (fib(10) + fib(9))) (((fib(10) + fib(9)) + (fib(9) + fib(8)))
= ... //a ton more calls
The terrible runtime might be causing your program to hang, as increasing fib(n) by 1 means you have a TON more recursive calls
your program overflows as Kevin L explained.
instead, you can use an iterative algorithm like this:
def fib (n)
return 0 if n == 0
return 1 if n == 1 or n == 2
x = 0
y = 1
(2..n).each do
z = (x + y)
x = y
y = z
end
return y
end
(0..14).map { |n| fib(n) }
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
I tried comparing the run time of two fibonacci methods on repl.it
require 'benchmark'
def fib_memo(n, memo = {})
if n == 0 || n == 1
return n
end
memo[n] ||= fib_memo(n-1, memo) + fib_memo(n-2, memo)
end
def fib_naive(n)
if n == 0 || n == 1
return n
end
fib_naive(n-1) + fib_naive(n-2)
end
def time(&block)
puts Benchmark.measure(&block)
end
time {fib_memo(14)}
time {fib_naive(14)}
Output
0.000000 0.000000 0.000000 ( 0.000008)
0.000000 0.000000 0.000000 ( 0.000099)
As you can see, the runtime is quite different. As #Uri Agassi suggested, use memoization. The concept is explained quite well here https://stackoverflow.com/a/1988826/5256509
Write a function that prints out all the factors for each of the numbers 1 through 100.
Really amateur coder but here's my attempt so far.
def factors_numbers(n1,n2)
(n1..n2).each do |n|
factors = []
factors << 1 ##every number has a factor of 1
factors << n ##every number is a factor of itself
i = 1
while i < n
new_number = n % (n-i)
if new_number == 0 #if 0, divisible and that means two numbers are factors
factors << new_number
factors << (n-i)
end
i += 1
end
return factors
end
end
Here is an improved version of your code:
def factors_numbers(n1,n2)
all_factors = {}
(n1..n2).each do |n|
factors = []
(1..Math.sqrt(n).floor).each do |i|
remainder = n % i
if remainder == 0 #if 0, divisible and that means two numbers are factors
factors << i
factors << n/i
end
end
factors = factors.sort.uniq
puts "Factors of #{n}: #{factors.join(',')}"
all_factors[n]=[factors]
end
return all_factors
end
Do you want unique factors? That is, in the range 1-100, should I get the number 1 a hundred times, or only once?
The easiest way to do this is by leveraging the "inject" Enumerable method.
def find_all_factors_between(n1,n2)
(n1..n2).inject([]) do |factors, num|
factors + (1..num).inject([]) { |arry, test| num % test == 0 ? arry + [test] : arry }
end
end
One final thing to note is that Ruby has implicit returns; that is, as long as the output of the last line of your method is your factors variable, you don't have to say return factors.
And my entry would be:
def find_all_factors_between(n1, n2)
factors = -> (n) { (1..n).select {|i| n % i == 0} }
(n1..n2).each { |n| puts "Factors of #{n}: #{factors.(n).join(', ')}" }
end
find_all_factors_between(1,100)
Well, if you wanted to do it with enumerables, there's always
def factor_numbers(rng)
factors = rng.map do |n|
(1..Math.sqrt(n).floor) # search numbers <= square root
.select { |d| n % d == 0 } # find factors <= square root
.flat_map { |x| [x, n / x] } # combine with factors >= square root
.sort # order from least to greatest
.uniq # remove dupes (basically the square root)
end
Hash[rng.zip(factors)] # rng = keys, factors = values
end
puts factor_numbers(1..100)
It's not the most efficient, but my point is just that many of the for/while constructs you'd see in languages like C or JavaScript can be expressed in other ways in Ruby.
(n1..n2).each{|x| print "#{x}: #{(1..x).select{|y| x % y == 0}}\n"}
That oughta do it :)
edit: Implemented Cary Swoveland's suggestion
def factor_nums(n1,n2)
all_factors = {}
(n1..n2).each do |n|
factors = []
(1..n).each do |i|
remainder = n % i
factors << i if remainder == 0
end
all_factors[n] = factors
end
return all_factors
end