i think my code is correct - yet i do not return an array in time for N = 200. Error is "Terminated due to timeout"
what can i do to improve the performance of this code?
def is_palindrome? (n)
n.to_s==n.to_s.reverse
end
def is_prime? (n)
return false if n< 2
(2..Math.sqrt(n)).none? {|f| n % f == 0}
end
prime_palindrome =-> (n) do
1.upto(Float::INFINITY).lazy.select { |n| is_prime?(n) && is_palindrome(n) }.first(n)
end
n = gets.to_i
p prime_palindrome.call(n)
Ruby knows how to do this faster.
require 'prime'
Prime.each.lazy.
select { |p| p.to_s.then { |s| s == s.reverse } }.
take(200).to_a
Lazy enumerators (as used in #Amadan's answer) are useful but seem to have a reputation for being somewhat slow. I thought it might be interesting to do a simple benchmark here, comparing Amadan's answer with a straightforward calculation using a while loop.
require 'prime'
Lazy enumerator
def amadan(n)
Prime::EratosthenesSieve.instance.send(:initialize)
Prime.each.lazy.
select { |p| p.to_s.then { |s| s == s.reverse } }.
take(n).to_a
end
while loop
def cary(n)
Prime::EratosthenesSieve.instance.send(:initialize)
arr = []
enum = Prime.each
while n > 0
p = enum.next
s = p.to_s
if s == s.reverse
arr << p
n -= 1
end
end
arr
end
The first line of each method, Prime::EratosthenesSieve... is included to make the benchmark more realistic. See the discussion in the comments.
Benchmark
require 'fruity'
#
n = 200
compare(amadan: -> { amadan(n) }, cary: -> { cary(n) })
Running each test once. Test will take about 10 seconds.
cary is faster than amadan by 10.000000000000009% ± 1.0%
Results are similar for other values of `n`.
Related
I am solving the Permutational Primes Kata using Ruby. I manage to find out Brute-force solution but it exceeds the time limits. I need to optimize my code but I don't have any idea how to do this. The Kata.
require 'prime'
def permutational_primes(n_max, k_perms)
result_h = {}
result_keys = []
Prime.each(n_max) do |prime|
perms = prime.digits.permutation.to_a.map(&:join).map(&:to_i).uniq
prime_no_length = prime.to_s.length
perms = perms.delete_if { |el| el.to_s.length < prime_no_length }
# elimianate number greater than n_max
perms = perms.delete_if { |el| el > n_max }
next if (perms & result_keys).any?
perms = perms.delete_if { |el| !Prime.prime?(el) }
# minus one because we include
if perms.count - 1 == k_perms
result_h[prime] = perms
result_keys.append(prime)
end
end
return [0, 0, 0] if result_keys.empty?
[result_h.count, result_keys[0], result_keys[result_keys.count-1]]
end
Some low-hanging fruit:
Benchmarking is one way to understand what parts are more computationally expensive than others (likely Prime.prime?)
Find work that you're doing repeatedly or checks for information that you already know every Prime.each loop and cache it, trading memory for computation, e.g. Prime.prime?
All the common Enumerable methods create new Arrays. Instead, reuse existing arrays, e.g. map!
I have not yet thoroughly tested the following, but this general approach should speed things up considerably. There are two main elements that improved efficiency: use of the method Prime::each and maintaining a set of prime permutations already tested, to avoid unnecessary testing of duplicates.
require 'prime'
require 'set'
def permutational_primes(nMax, permutes)
skips = Set.new
enum = Prime.each
arr = []
while (prime = enum.next) < nMax
next if skips.include?(prime)
a = prime.digits.permutation.with_object([]) do |perm,a|
next if perm[-1].zero?
n = perm.reverse.join.to_i
if n < nMax && !skips.include?(n) && Prime.prime?(n)
skips << n
a << n
end
end
a.each { |n| skips << n }
next if a.size != permutes + 1
arr << a.min
end
[arr.size, arr.size.zero? ? 0 : arr.min, arr.size.zero? ? 0 : arr.max]
end
permutational_primes(1000, 3)
#=> [3, 149, 379]
This passes all tests but times out. I'm working on another optimization.
Explanation is under construction...
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.
I have an array with +20000 integer elements.
I want to create a new array where each element in the old array is added a modifying number. On a small sample array it would look like this:
old_array = [2,5,6,8]
modifying_number = 3
new_array = [5,8,9,11]
Is there any more efficient way than doing an iteration like this?
class Array
def addition_by(x)
collect { |n| n + x }
end
end
No. N iterations are the minimal complexity of this algorithm.
You can do it in place by modifying source array with collect!(if you for some reasons not need a source array). Complexity will be the same, additional big object will not created.
20k records is not much to worry about performance.
ary = Array.new(20000) { 1 }
ary.map! { |el| el + 1 }
would work totally fine.
I would just suggest to modify the initial array inplace instead of creating a new one (using method with bang), so it will definitely use less resources.
I guess it would mean implementing map in another way? This question deals with such a task. I've included benchmarks of the answers by #JörgWMittag and #uishra. Although it has to be said speed was not a requirement in the linked question so the answers cannot be criticised in that regard. I've also included #CarySwoveland's answer from this question.
require 'fruity'
require 'matrix'
class Array
#jörg_w_mittag
def new_map
return enum_for(__callee__) unless block_given?
inject([]) {|acc, el| acc << yield(el) }
end
#uishra
def my_map(&block)
result = []
each do |element|
result << block.call(element)
end
result
end
#cary_swoveland
def vec_map(k)
(Vector[*[k]*self.size] + Vector[*self]).to_a
end
end
arr = (1..30000).to_a
k = 3
10.times do
compare do
core_map { ar = arr.dup; ar.map { |n| n + k } }
jörg_w_mittag { ar = arr.dup; ar.new_map { |n| n + k } }
uishra { ar = arr.dup; ar.my_map { |n| n + k } }
cary_swoveland { ar = arr.dup; ar.vec_map k }
end
puts
end
A summary of the results/output:
Results on five occasions
#Running each test once. Test will take about 1 second.
#core_map is faster than jörg_w_mittag by 2x ± 1.0
#jörg_w_mittag is similar to uishra
#uishra is similar to cary_swoveland
Results on two occasions
#Running each test once. Test will take about 1 second.
#core_map is faster than jörg_w_mittag by 2x ± 0.1
#jörg_w_mittag is similar to uishra
#uishra is similar to cary_swoveland
Results on three occasions
#Running each test once. Test will take about 1 second.
#core_map is faster than uishra by 2x ± 1.0
#uishra is similar to jörg_w_mittag
#jörg_w_mittag is similar to cary_swoveland
require 'matrix'
class Array
def vec_map(k)
(Vector[*[k]*self.size] + Vector[*self]).to_a
end
end
[1,2,3].vec_map 4
#=> [5, 6, 7]
I'm trying to write a program in Ruby that finds the prime factors of a given number, without using Ruby's .Prime class. The code I wrote seems logical (if roundabout) to me, but for some reason the last line of code doesn't seem to work and I have no idea why. The code still just returns all of the factors of a given number, not the prime ones.
def prime(n)
array = []
r = Range.new(2, n - 1)
r.each { |x| array << x if n % x == 0 }
array.each { |x| puts x if (2..x - 1).each { |p| x % p != 0 }}
end
You want to check .all? numbers in (2..x - 1), not .each:
def prime(n)
array = []
r = Range.new(2, n - 1)
r.each { |x| array << x if n % x == 0 }
array.each { |x| puts x if (2..x - 1).all? { |p| x % p != 0 }}
end
By the way, I would also recommend to give meaningful names to your variables, because now it's really hard to read your code, this is much clearer implementation:
def prime?(num)
return false if num < 2
(2..Math.sqrt(num).to_i).each do |i|
return false if num % i == 0
end
true
end
def prime_factors(num)
(2..num - 1).inject([]) do |factors, i|
(num % i == 0) ? factors << i : factors
end.select { |factor| prime?(factor) }
end
p prime_factors(44)
def prime_factors(n)
# It's clear what factors will hold.
# It helps you when you or someone else read it out
# after a while.
factors = []
# Keep the r. No problem.
r = Range.new(2, n-1)
# Array#select is nice for this task.
# select is good in case where you need to filter out certain
# values out of a list. It nicely separates the selection task.
factors = r.select { |x| n % x == 0 }
# It's better not to go for double block on a single line.
# It will become more readable this way.
# Also it's better to handle how the result is displayed outside
# the function and just to return the computed values.
factors.select do |x|
(2..x - 1).all? { |p| x % p != 0 }
end
end
It seems more logical to split this single function into three factors n, prime n, and prime_factors n then compose them together. This design is more modular and more suitable to testing the individual parts. e.g. If all of the logic is globbed together, how can you say for certain that your program find primes correctly?
def factors n
(2..(n/2).floor).select {|x| n % x == 0 }
end
def prime? n
return false unless n >= 2
(2..Math.sqrt(n).floor).all? {|x| n % x != 0 }
end
def prime_factors n
factors(n).select {|x| prime? x }
end
Whats the best way in Ruby to do something like my_array.select(n){ |elem| ... }, where the n means "I only want n elements returned, and stop evaluating after that number is reached"?
This should do the trick:
my_array.select(n) { |elem| elem.meets_condition? }.take(n)
However, this will still evaluate all items.
If you have a lazy enumerator, you could do this in a more efficient manner.
https://github.com/ruby/ruby/pull/100 shows an attempt at enabling this feature.
You can easily implement lazy_select:
module Enumerable
def lazy_select
Enumerator.new do |yielder|
each do |e|
yielder.yield(e) if yield(e)
end
end
end
end
Then things like
(1..10000000000).to_enum.lazy_select{|e| e % 3 == 0}.take(3)
# => [3, 6, 9]
execute instantly.
Looks like there's no avoiding a traditional loop if you're using stock 1.8.7 or 1.9.2...
result = []
num_want = 4
i = 0
while (elem = my_array[i]) && my_array.length < num_want
result << elem if elem.some_condition
i += 1
end
You could make an Enumerable-like extension which has your desired selectn semantics:
module SelectN
def selectn(n)
out = []
each do |e|
break if n <= 0
if yield e
out << e
n -= 1
end
end
out
end
end
a = (0..9).to_a
a.select{ |e| e%3 == 0 } # [0, 3, 6, 9]
a.extend SelectN
a.selectn(1) { |e| e%3 == 0 } # [0]
a.selectn(3) { |e| e%3 == 0 } # [0, 3, 6]
# for convenience, you could inject this behavior into all Arrays
# the usual caveats about monkey-patching std library behavior applies
class Array; include SelectN; end
(0..9).to_a.selectn(2) { |e| e%3 == 0 } # [0,3]
(0..9).to_a.selectn(99) { |e| e%3 == 0 } # [0,3, 6, 9]
Why not flip this around and do the #take before the #select:
my_array.take(n).select { |elem| ... }
That will ensure you only do your computation for n number of items.
EDIT:
Enumerable::Lazy is known to be slower, but if your computation is known to be more computationally expensive than the lazy slowness, you can use the Ruby 2.0 feature:
my_array.lazy.select { |elem| ... }.take(n)
See: http://blog.railsware.com/2012/03/13/ruby-2-0-enumerablelazy/
I guess broken loop can be done in old-fashioned loop style with break or something like this:
n = 5
[1,2,3,4,5,6,7].take_while { |e| n -= 1; n >= 0 && e < 7 }
In functional language this would be recursion, but without TCO it doesn't make much sense in Ruby.
UPDATE
take_while was stupid idea as dbenhur pointed out, so I don't know anything better than a loop.