List the factors of a non-prime number - ruby

My goal is to display if a number is prime, and if it is not, list all of its factors. If I input 6, the program should return:
6 is not a prime number => 2, 3
Here is what I have so far:
puts "Enter a number: "
num = gets
num = num.to_i
def prime(num)
is_prime = true
for i in 2..num-1
if num % i == 0
is_prime = false
end
end
if is_prime
puts "#{num} is prime!"
else
puts "#{num} is not prime!"
end
end
prime(num)
I tried making a while loop for this but I can't seem to make it work. I'm not sure if I am using the num%i==0 formula correctly. Any help would be appreciated.

If permitted to do so, use the Standard Library class Prime.
require 'prime'
def is_prime? n
n.prime? ? n : Prime.prime_division(n)
end
p is_prime? 6 #=> [[2, 1], [3, 1]]
p is_prime? 11 #=> 11
p is_prime? 100 #=> [[2, 2], [5, 2]]

Homework hint 1)
You need to change the following things in order to get all the factors:
do not stop as soon as you find one factor
(which your prime-finder code inefficiently does not do anyway...)
print each factor you find
If you also need the correct exponent you further need to
check for each found factor whether it is still a factor after dividing by it,
this needs to be done in a loop
Homework hint 2)
In order to get a specific desired output, print the decoration (e.g. "," and newlines) explicitly when it is needed.
Printing the statement first and only once can be done by using a flag for "already printed" and checking it before printing the statement in the loop.
(I assume that this is a homework question and am therefor intentionally not giving a complete solution, according to the compromise desccribed here How do I ask and answer homework questions?
Thank you for not minding my assumption, or so I gather from your accepting my answer. In case it is not about homework I assume that you appreciated the help and the way of helping, in spite of my mistake.)

require 'prime'
def factors(n)
first, *rest =
Prime.prime_division(n).map { |n,power| [n].product((0..power).to_a) }
first.product(*rest).map { |a| a.reduce(1) { |t,(n,power)| t * n**power } }
end
Let's use this method to compute the factors of 1500.
factors 1500
#=> [ 1, 5, 25, 125,
# 3, 15, 75, 375,
# 2, 10, 50, 250,
# 6, 30, 150, 750,
# 4, 20, 100, 500,
# 12, 60, 300, 1500]
Note that
Prime.prime_division(1500)
#=> [[2, 2], [3, 1], [5, 3]]
and
Prime.prime_division(500).map { |n,power| [n].product((0..power).to_a) }
#=> [[[2, 0], [2, 1], [2, 2]], [[5, 0], [5, 1], [5, 2], [5, 3]]]
Moreover, factors(n).size equals 2 if and only if n is prime. For example,
factors(37)
#=> [1, 37]
Prime.prime?(37)
#=> true
See Prime::prime_division.

Related

Codewars exercise "Count by X" not working

I'm tryng to do this exercise:
Create a function with two arguments that will return a list of length
(n) with multiples of (x).
Assume both the given number and the number of times to count will be
positive numbers greater than 0.
Return the results as an array (or list in Python, Haskell or Elixir).
Examples:
count_by(1,10) #should return [1,2,3,4,5,6,7,8,9,10]
count_by(2,5) #should return [2,4,6,8,10]
Quite easy, nothing to say. BUT I really do not understand why my code is not working.
PLease DO NOT GIVE ME NEW CODE OR SOLUTION, I JUST WANT TO UNDERSTAND WHY MINE DOESN'T WORK.
My solution:
def count_by(x, n)
arrays = []
arrays.push(x)
valore_x = x
unless arrays.count == n
arrays.push( x + valore_x)
x += valore_x
end
return arrays
end
count_by(3, 5)
ERROR MESSAGE =
Expected: [1, 2, 3, 4, 5], instead got: [1, 2]
✘ Expected: [2, 4, 6, 8, 10], instead got: [2, 4]
✘ Expected: [3, 6, 9, 12, 15], instead got: [3, 6]
✘ Expected: [50, 100, 150, 200, 250], instead got: [50, 100]
✘ Expected: [100, 200, 300, 400, 500], instead got: [100, 200].
So looks like that my code do not put all the numbers. Thanks.
Now you have answer on your question, so I just recommend one more variant of solution, I think it's more ruby-way :)
def count_by(x, y)
y.times.with_object([]) do |i, result|
result << x*(i+1)
end
end
Change
unless arrays.count == n
to
until arrays.count == n
unless is not a loop. It's just like an if, but the code is executed if the condition is false.
until is just like while, but the code is executed while the condition is false.
Array::new can be used here.
def count_by(x, n)
Array.new(n) { |i| x*(i+1) }
end
count_by(1,5) #=> [1, 2, 3, 4, 5]
count_by(2,5) #=> [2, 4, 6, 8, 10]
count_by(3,5) #=> [3, 6, 9, 12, 15]
count_by(50,5) #=> [50, 100, 150, 200, 250]
count_by(100,5) #=> [100, 200, 300, 400, 500]
count_by(0,5) #=> [0, 0, 0, 0, 0]
Just a few other ways to achieve the same result. Using Numeric#step:
x.step(by: x, to: x*y).entries
shorter but less readable:
x.step(x*y, x).entries
or using a range with Range#step:
(x..x*y).step(x).entries
In each of the examples entries can be replaced with to_a

error in modulus method in ruby

I am trying to write a method that takes in an array as an argument and returns an array of the numbers in the argument that are have both an even index number and an even value. I am not sure why, but it is giving me the error "undefined method %" in line 5. Can someone explain how I can fix this?
def odd_value_and_position(array)
newArray=[] #create new array
i=0 #i=0
while i <= array.length #loop while
newArray.push(array[i]) if array[i] % 2 != 0
i = i + 2
end
return newArray
end
puts odd_value_and_position([0,1,2,3,4,5])
Another way to do this:
def evens arr
arr.select.with_index { |e,i| e.even? && i.even? }
end
evens [0,1,2,3,4,5] #=> [0,2,4]
When i is equal to array.length, array[i] is nil.
What is nil % 2? It is undefined.
def odd_value_and_position(array)
newArray=[] #create new array
i=0 #i=0
while i < array.length #loop while
newArray.push(array[i]) if array[i] % 2 != 0
i = i + 2
end
return newArray
end
puts odd_value_and_position([0,1,2,3,4,5]) #=> []
puts odd_value_and_position([1,2,3,4,5]) #=> [1,3,5]
Due to the fact that the first element in a Ruby Array has 0 as index, I'm not sure you get the result you expected. See examples in code.
A more Rubyish example would be :
def odd_value_and_position(array)
array.select.with_index(1){|x,i| x.odd? && i.odd?}
end
puts odd_value_and_position([1,2,3,4,5]) #=> [1,3,5]
If I understand the question right, I'd go with something like:
def some_method_name(array)
array.select.with_index { |*ij|
ij.all?(&:even?)
}
end
puts some_method_name([0, 1, 2, 3, 4, 5, 10, 13, 21, 22, 30])
# >> 0
# >> 2
# >> 4
# >> 10
# >> 30
Here's what it's doing:
def some_method_name(array)
array.select.with_index { |*ij|
ij # => [0, 0], [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [10, 6], [13, 7], [21, 8], [22, 9], [30, 10]
ij.all?(&:even?) # => true, false, true, false, true, false, true, false, false, false, true
}
end
puts some_method_name([0, 1, 2, 3, 4, 5, 10, 13, 21, 22, 30])
# >> 0
# >> 2
# >> 4
# >> 10
# >> 30
There are a couple problems with the original code.
Using while loops easily leads to problems with off-by-one errors, or loops that never trigger, or loops that never end.
To combat that in Ruby, we use each and map, select, reject or similar iterators to loop over the array, and process each element in turn, then base the logic on that.
array.select is looking at each element and applying the logic in the block, looking for "truthy" results. with_index adds the index of the iteration as a second value passed into the block. *id turns the two values being passed in into an array, making it easy to apply all? and its even? test. If even? returns true to both then all? triggers and returns true again which signals to select to return that element of the array.

What is the right way to write ruby code?

I am solving the pyramid problem, in which an array is reduced to a single element over time by subtracting two consecutive numbers in each iteration.
input: [1, 5, 9, 2, 3, 5, 6]
iterations
[4, 4, -7, 1, 2, 1],
[0, -11, 8, 1, -1],
[-11, 19, -7, -2],
[30, -26, 5],
[-56, 31],
[87]
output: 87
What is the best way or ruby way to solve this problem? This can be done by inheriting array and making a new class, but I don't know how. Please help. I write this code to solve it:
a = [1,5,9,2,3,5,6]
class Array
def pyr
a = self.each_cons(2).to_a.map! { |e| e[1] - e[0] }
a
end
end
while a.length > 1
a = a.pyr
ans = a[0]
end
p ans
I see three ways to approach this.
Reopen the Array class
Sure, if in your particular ruby script/project this is an elementary functionality of an array, reopen the class. But if you are going to re-open a class, at least make sure the name is something meaningful. pyr? Why not write a full name, so no conflicts are possible, something like next_pyramid_iteration (I have never heard of this pyramid problem, so excuse me if I am way of base here).
Make a class inherit from Array
class Pyramid < Array
def next_iteration
self.each_const(2).map! { |e| e[1] - e[o] }
end
end
and then your calculation would become something like
pyramid = Pyramid.new([1,5,9,2,3,5,6])
while pyramid.length > 1
pyramid.next_iteration
end
pyramid[0]
Make a specific class to do the calculation
I am not quite sure what you are trying to achieve, but why not just make a specific class that knows how to calculate pyramids?
class PyramidCalculator
def initialize(arr)
#pyramid = arr
end
def calculate
while #pyramid.length > 1
do_next_iteration
end
#pyramid.first
end
def self.calculate(arr)
PyramidCalculator.new(arr).calculate
end
protected
def do_next_iteration
#pyramid = #pyramid.each_const(2).map! { |e| e[1] - e[o] }
end
end
because I added a convenience class-method, you can now calculate a result as follows:
PyramidCalculator.calculate([1,5,9,2,3,5,6])
My personal preference would be the last option :)
I would just do it as a two-liner.
a = a.each_cons(2).map{|e1, e2| e2 - e1} while a[1]
a.first # => 87
It's certainly easy enough to turn this into a simple function without hacking on the Array class:
def pyr(ary)
return ary[0] if ary.length < 2
pyr(ary.each_cons(2).map { |e| e[1] - e[0] })
end
p pyr [1,5,9,2,3,5,6] # => 87
Use return ary if you want the answer as a one-element array rather than a scalar.
If you prefer iteration to recursion or have a very large array:
def pyr(ary)
ary = ary.each_cons(2).map { |e| e[1] - e[0] } while ary.length > 1
ary
end
By encapsulating this as a function rather than doing it inline, you get the ability to do the operation on any number of arrays plus it's non-destructive on the original input array.
It's not necessary to compute the end value by successive computation of differences, which requires (n*(n-1)/2 subtractions and the same number of additions, where n is the size of the array a. Instead, we can compute that value by summing n terms of the form:
(-1)K+ibin_coeff(n-1,i)*a[i]
for i = 0..(n-1), where:
K equals 0 if the array has an even number of elements, else K equals 1; and
bin_coeff(n,i) is the binomial coefficient for choosing "n items i at a time" (n!/i!*(n-i)!).
I know what you're thinking: the calculation of each binomial coefficient will take some work. True, but that can be done in an efficient way (which I've not done below), by computing bin_coeff(n-1,i+1) from bin_coeff(n-1,i), etc. Of course, that's academic, as no one is likely to actually use the method I'm suggesting.
(I'm hoping nobody will demand a proof, but I'll try to oblige if a request is made.)
Code
class Fixnum
def factorial
(1..self).reduce(1) { |t,i| t*i }
end
def bin_coeff m
self.factorial/(m.factorial*(self-m).factorial)
end
end
def pyramid_sum(a)
n = a.size-1
sign = n.even? ? -1 : 1
(0..n).reduce(0) do |t,i|
sign = -sign
t + sign * n.bin_coeff(i) * a[i]
end
end
Examples
pyramid_sum [1, 5] #=> 4
pyramid_sum [1, 5, 9] # #=> 0
pyramid_sum [1, 5, 9, 2] #=> -11
pyramid_sum [1, 5, 9, 2, 3] #=> 30
pyramid_sum [1, 5, 9, 2, 3, 5] #=> -56
pyramid_sum [1, 5, 9, 2, 3, 5, 6] #=> 87

Inserting values at empty indexes in arrays. How can I write this code shorter or more modular?

I have the following code I wrote which takes a 2d array with arrays of varying length and appends the value 0 to every index until all arrays are of the same length.
Can this code be written shorter or more efficient and modular?
a = [[1,7],[2,3],[5,1,2],[3],[1],[]]
l = a.map(&:length).max
a2 = a.each{|e| e.push(Array.new(l - e.length, 0) )}
a2.each{|e| e.flatten!}
#=> [[1, 7, 0], [2, 3, 0], [5, 1, 2], [3, 0, 0], [1, 0, 0], [0, 0, 0]]
UPDATE
Because I feel unable to award an accepted answer to the two answers given thus far based on the simplicity of the written code itself, I have decided to award it based on the efficiency of the running speed of the code.
100 test cases running code block 10000 times.
#My Code:
#average run time of test case -> 0.24267sec
#standard deviation -> 0.00735sec
#Stefan’s Code:
#average run time of test case -> 0.06389sec
#standard deviation -> 0.00756sec
#steenslag’s Code:
#average run time of test case -> 0.0577sec
#standard deviation -> 0.00413sec
tests were conducted under the same conditions using a custom written ruby timer class I made and are only relative to each other and my crappy 2010-macbookpro on which I ran them.
Another option using Array#fill:
l = a.map(&:length).max
a.each { |e| e.fill(0, e.length...l) }
a #=> [[1, 7, 0], [2, 3, 0], [5, 1, 2], [3, 0, 0], [1, 0, 0], [0, 0, 0]]
The flatten could be avoided by splatting the array:
l = a.max_by(&:size).size
a2 = a.each{|e| e.push(*Array.new(l - e.length, 0) )}
One more way, four days late:
len = a.map(&:size).max
a.map { |e| Array.new(len) { |i| e[i].to_i } }
#=> [[1,7,0],[2,3,0],[5,1,2],[3,0,0],[1,0,0],[0,0,0]]

Recursion involving an Array for Wonky Coins

Here's the prompt I've been given:
Catsylvanian money is a strange thing: they have a coin for every
denomination (including zero!). A wonky change machine in
Catsylvania takes any coin of value N and returns 3 new coins,
valued at N/2, N/3 and N/4 (rounding down).
Write a method wonky_coins(n) that returns the number of coins you
are left with if you take all non-zero coins and keep feeding them
back into the machine until you are left with only zero-value coins.
Difficulty: 3/5
describe "#wonky_coins" do
it "handles a simple case" do
wonky_coins(1).should == 3
end
it "handles a larger case" do
wonky_coins(5).should == 11
# 11
# => [2, 1, 1]
# => [[1, 0, 0], [0, 0, 0], [0, 0, 0]]
# => [[[0, 0, 0], 0, 0], [0, 0, 0], [0, 0, 0]]
end
it "handles being given the zero coin" do
wonky_coins(0).should == 1
end
end
Maybe it's because of the tests given that involve arrays, but I couldn't get my mind off of them! So my solution so far is as follows:
def wonky_coins(n)
arr = []
arr << n/2 << n/3 << n/4
#base case?
if arr.all?{|coin| coin == 0}
return arr.flatten.length
else
arr.map{|x| wonky_coins(x)}
end
end
p wonky_coins(5)
Except I get [[3,3,3],3,3] as an output if I map it. It's not actually recurring, but even before that, it's giving a strange output that I can't for the life of me understand why the output is this way!
I know it's because I'm using the map method, is it because I'm mutating it while iterating it through wonky_coins again that I'm getting this strange output I can't explain?
I've since looked at the solution and realized that arrays made it needlessly complicated, but I'm still wondering what's going on here??
Here's what Seeing is Believing shows as the code runs:
def wonky_coins(n)
arr = [] # => [], [], [], [], [], [], []
arr << n/2 << n/3 << n/4 # => [2, 1, 1], [1, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]
#base case?
if arr.all?{|coin| coin == 0} # => false, false, true, true, true, true, true
return arr.flatten.length # => 3, 3, 3, 3, 3
else
arr.map{|x| wonky_coins(x)} # => [3, 3, 3], [[3, 3, 3], 3, 3]
end
end
p wonky_coins(5) # => [[3, 3, 3], 3, 3]
# >> [[3, 3, 3], 3, 3]
Seeing is Believing is a great tool and can help dig out weirdness in code.

Resources