I've seen solutions posted in other languages but not Ruby so I'm asking here.
Trying to find out the largest prime factor of 13195.
My code is as follows
# find out all numbers that divide without remainder into 13195
array = []
count = 2
13195.times do
if 13195 % count == 0
array.push(count)
end
count += 1
end
#From those numbers that divide cleanly into 13195, find out which are prime aka can only be divided by themselves and 1
new_count = 2
primes = 0
array.each do |x|
while new_count < x
if x % new_count != 0
else
if x > primes
primes = x
end
end
new_count += 1
end
end
puts primes
In my first loop I am populating an empty array with all the numbers that divide into 13195 without a remainder, from testing this piece of code seems to be working.
It's the second part of my solution that's the problem inside my each statement, can someone point me in the right direction?
I suggest you use Prime#prime_division:
require 'prime'
def largest_prime_factor(n)
Prime.prime_division(n).max_by(&:first).first
end
largest_prime_factor(13195)
#=> 29
(1..1000).to_a.sample(15).sort.each {|n| puts "%3d: %3d" % [n, largest_prime_factor(n)]}
61: 61
80: 5
88: 11
250: 5
304: 19
414: 23
514: 257
548: 137
679: 97
716: 179
754: 29
770: 11
906: 151
907: 907
968: 11
For example,
n = 13195
a = Prime.prime_division(n)
#=> [[5, 1], [7, 1], [13, 1], [29, 1]]
b = a.max_by(&:first)
#=> [29, 1]
b.first
#=> 29
It appears that the elements of the array returned by prime_division are in order of increasing prime factor. If that were guaranteed, one could just write:
Prime.prime_division(n).last.first
I used max_by in the event that the order of those elements is implementation-specific.
Shorter version:
require 'prime'
primes = Prime.each(13195).to_a
upper = primes.last
primes will have all primes from 0 to 13195 and upper obviously the last.
I set a limit of prime numbers to 100000 (to avoid of couple days of calculation of big numbers like 600851475143 =) )
def prime_factors(n)
prime_array = []
p = 2
if n < 2
return p
end
while p < n && p < 1000000
if n % p == 0
prime_array.push(p)
end
p +=1
end
primes = []
prime_array.size.times do |i|
if n > 1
n = n / prime_array[i]
primes.push(prime_array[i])
end
end
return primes.last
end
#prime_factors(600851475143)
puts prime_factors(600851475143)
#prime_factors(13195)
puts prime_factors(13195)
Another way to use prime_division:
require 'prime'
(13195).prime_division.map(&:first).max
=> 29
Your second loop can be re-written to do what is meant to do.
As I understand, your goal is to select from array, largest of such elements that are prime (divides by only 1 and itself). In other words, an element x is eligible if it is not divisible by any number between 2 and x-1.
result = array.select {|x| not (2..x-1).any? {|i| x % i == 0} }.max
#=> 29
Currently, your logic has some flaws. It is not resetting the value of new_count and hence you are getting wrong results. Here is corrected version:
array.each do |x|
is_prime = true
while new_count < x
if x % new_count == 0
is_prime = false
end
new_count += 1
end
new_count = 2
primes = x if is_prime and x > primes
end
Without using Prime#prime_division we can dived the problems into small parts. the first part if to write a method that determine whether a number if prime or not, which can be like :
def prime?(num)
if num < 2
return false
end
(2...num).each do |ele|
if num % ele == 0
return false
end
end
return true
end
then we can write our main method which is asking for the prime_factors of a number like:
def prime_factors(num)
prime_facts = []
(1..num).each do |i|
if num % i == 0 && prime?(i)
prime_facts << i
end
end
return prime_facts
end
print prime_factors(24) #=> [2, 3]
puts
print prime_factors(60) #=> [2, 3, 5]
puts
print prime_factors(13195) # [5, 7, 13, 29]
puts
Related
I was just curious as to how to change a number from number base m to another base n with a Ruby program, not a gem. Has anyone done this and would like to share their thoughts or ideas? Just thought it would be fun to try out a program like this :)
I've done it for bin to dec, dec to bin, dex to hex, hex to dec, but would want to know how to do it from m to n.
def bin2dec(num)
sum = 0
i = 0
while i < num.length
sum += 2 ** i * num[num.length - i - 1].to_i
i += 1
end
return sum
end
bin = gets.chomp
out = bin2dec(bin)
print out
def dec2bin(dec)
out = ""
num = dec
while num != 0
out = "#{num % 2}" + out
num = num / 2
end
return out
end
dec = gets.to_i
print dec2bin(dec)
These functions are built in.
To convert "EFFE" from base 16 (hex) to base 8 (octal)...
"EFFE".to_i(16).to_s(8)
# => "167776"
To put this in a method...
def convert_base(string, from_base, to_base)
string.to_i(from_base).to_s(to_base)
end
If you want a method which converts any positive base to any other positive base, start looking at Integer#digits. It takes an argument (10 by default), but nothing stops you from getting a number in base 543.
For 11 <= n <= 36, Ruby has a convention that allows integers to be expressed in base n with the 10 digits 0-9 and the first n-10 characters of the alphabet. It is for that reason that we obtain the following results:
1270.to_s(36) #=> "za"
"za".to_i(36) #=> 1270
1270.to_s(37) #=> ArgumentError (invalid radix 37)
"za".to_i(37) #=> ArgumentError (invalid radix 37)
Ruby's representation of integers, however, is just a convention.
I will only deal with non-negative integers and will refer to them as "numbers". Negative integers can be negated, converted to a number of a different base and then that number negated.
We could express numbers of any base as arrays of digits, where each digit is expressed as a base 10 integer. For example, we could write:
46 in base 10 as [4, 6]
za in base 36 as [36, 10]
a two-digit base N number as [n, m], where n and m are both between 0 and N-1.
We can write a method to convert a base 10 number to this array representation:
def base10_to_base_n(n10, radix)
arr = []
while n10 > 0
n10, rem = n10.divmod(radix)
arr << rem
end
arr.reverse
end
base10_to_base_n(123, 10)
#=> [1, 2, 3]
base10_to_base_n(131, 2)
#=> [1, 0, 0, 0, 0, 0, 1, 1]
abase10_to_base_n(1234, 16)
#=> [4, 13, 2]
base10_to_base_n(9234, 99)
#=> [93, 27]
Note that, in the third example:
4*(16**2) + 13*(16**1) + 2*(16**0) #=> 9234
Next we create a method that does the reverse: converts a number in a given base, described as an array of digits (the argument base_n) to a base 10 number.
def base_n_to_base_10(base_n, radix)
pow = 1
arr = base_n.reverse
base_n.reverse.reduce do |n10, digit|
pow *= radix
n10 + digit*pow
end
end
base_n_to_base_10([1, 2, 3], 10)
#=> 123
base_n_to_base_10([1, 0, 0, 0, 0, 0, 1, 1], 2)
#=> 131
base_n_to_base_10([4, 13, 2], 16)
#=> 1234
base_n_to_base_10([93, 27], 99)
#=> 9234
As expected, if
radix = 87
n10 = 6257
base87 = base10_to_base_n(n10, radix)
#=> [71, 80]
then:
base_n_to_base_10(base10_to_base_n(n10, radix), radix)
#=> 6257
base10_to_base_n(base_n_to_base_10(base87, radix), radix)
#=> [71, 80]
If you wanted to do it without the built-in methods...
def convert_base(string, from_base, to_base)
characters = (0..9).to_a + ('A'..'Z').to_a
string = string.to_s.upcase.gsub(/[^0-9A-Z]/i, '') # remove non alphanumeric
digits = string.split('')
decimal_value = digits.inject(0){|sum, digit| (sum * from_base) + characters.find_index(digit) }
result = []
while decimal_value > 0
result << characters[decimal_value % to_base]
decimal_value = decimal_value / to_base
end
result = result.join.reverse
return result if result.length > 0
'0'
end
convert_base('effe', 16, 8)
# => "167776"
I've been using a piece of Ruby code that I found here.
Here's the code:
a = [1, 4, 7, 13]
def add(ary, idx, sum)
(idx...ary.length).each do |i|
add(ary, i+1, sum + ary[i])
end
puts sum
end
add(a, 0, 0)
Thing is, I don't need it to spit out the results of adding all the sums. I need the min, max, median, and average of the sums.
How do I modify this code in order to get them? I'm a total beginner at Ruby. I've been using this code, and then transferring the results to Excel to get the values I want. But it feels like my methods could be more efficient.
Thank you for your help.
EDIT: Expected results - Currently the code spits this out on my screen:
25
12
18
5
21
8
14
1
24
11
17
4
20
7
13
0
I want it to spit out the min, average, median, and max instead:
0
12.5
12.5
25
a = [1, 4, 7, 13]
def all_sums(array)
combination_lengths = (0..array.length)
all_combinations = combination_lengths.flat_map do |c|
array.combination(c).to_a
end
all_combinations.map(&:sum)
end
def print_min_max_avg_med(array)
puts array.min
puts array.max
puts array.sum.to_f / array.length
sorted_arr = array.sort
puts sorted_arr[(array.length - 1) / 2] + sorted_arr[array.length / 2] / 2.0
end
print_min_max_avg_med(all_sums(a))
Ok, instead of outputting the values we can store them in an arrary and use that array for the values you need.
(edited after chewing out by Stefan Pochmann)
a = [1, 4, 7, 13]
def add(ary, idx, sum, results = nil)
unless results
results = []
first_run = true
end
(idx...ary.length).each do |i|
add(ary, i+1, sum + ary[i], results)
end
results << sum
if first_run
puts results.min
puts results.inject(&:+).to_f / results.size
puts (results.sort[((results.size - 1) / 2)] + results.sort[(results.size / 2)]) / 2.0
puts results.max
end
end
add(a, 0, 0)
Alright, after seeing the examples from Pochmann and Bronca, I put this together after googling for a better way to get the median.
a = [1, 4, 7, 13]
def all_sums(array)
combination_lengths = (0..array.length)
all_combinations = combination_lengths.flat_map do |c|
array.combination(c).to_a
end
all_combinations.map(&:sum)
end
def median(array)
sorted = array.sort
len = sorted.length
(sorted[(len - 1) / 2] + sorted[len / 2]) / 2.0
end
def print_min_max_avg_med(array)
puts array.min
puts array.empty? ? 0 : array.sum.to_f / array.length
puts median(array)
puts array.max
end
print_min_max_avg_med(all_sums(a))
I've run a few tests, and it seems to work for both odd and even arrays. Hope this is useful to the future somebody else stuck in my present position.
Thank you everyone who helped.
Min and Max
The min and max are easy.
def min_and_max_of_sums a
return [nil, nil] if a.empty?
negs, nonnegs = a.partition { |n| n < 0 }
[negs.any? ? negs.sum : nonnegs.min, nonnegs.any? ? nonnegs.sum : negs.max]
end
min_and_max_of_sums [1, 4, -5, 7, -8, 13]
#=> [-13, 25]
min_and_max_of_sums [1, 2, 3]
#=> [1, 6]
min_and_max_of_sums [-1, -2, -3]
#=> [-6, -1]
min_and_max_of_sums []
#=> [nil, nil]
Mean
Now consider the calculation of the mean.
If n is the size of the array a, there are 2n combinations of elements of a that contain between 0 and n elements.1 Moreover, there is a 1-1 mapping between each of those combinations and an n-vector of zeros and ones, where the ith element of the n-vector equals 1 if and only if the element ai is included in the combination. Note that there are 2n such n-vectors, one-half containing a 1 in the ith position. This means that one-half of the combinations contain the element ai. As i is arbitrary, it follows that each element of a appears in one-half of the combinations.
The mean of the sums of all elements of all combinations equals T/2n, where T is the sum of the sums of the elements of each combination. Each element ai appears in 2n/2 combinations, so its contribution to T equals (in Ruby terms)
a[i] * 2**(n)/2
As this hold for every element of a, the mean equals
a.sum * (2**(n)/2)/2**(n)
=> a.sum/2
Here's an example. For the array
a = [1, 4, 8]
the mean of the sums would be
a.sum/2
#=> 13/2 => 6.5
If we were to calculate the mean by its definition we would perform the following calculation (and of course get the same return value).
(0 + (1) + (4) + (8) + (1+4) + (1+8) + (4+8) + (1=4+8))/2**3
#=> (4*1 + 4*4 + 4*8)/8
#=> (1 + 4 + 8)/2
#=> 6.5
I will leave the calculating of the median to others.
1 Search for "Sums of the binomial coefficients" here.
So
#[11,13,17,23] => [13,17,19,29]
if the number isn't prime, then the function is just returning the number
#[11,8,2,24] => [13,8,3,24]
I'm having so much trouble with the very last number (29), for some reason, it's going into an infinite loop. I feel like there is such a simple solution, but it's just escaping me..
def next_prime(arr)
new_arr = []
arr.each do |num|
#puts num
if prime?(num)
p = false
i = num + 2
while !p
p = prime?(i)
i += 2
end
new_arr << i
else
new_arr << num
end
end
new_arr
end
EDIT: here is the prime function
def prime?(num)
if num ==1
return false
elsif num < 3
return true
elsif num % 2 == 0 || num % 3 == 0
return false
end
i = 5
while i*i <= num
if num % i == 0 || num % (i + 2) == 0
return false
end
i += 6
end
return true
end
The first array works decently for me, even the 29, except for the fact that everything is 2 higher than it should be, because you add 2 after you check if you have a prime which can be fixed by a slight alteration to the code:
if prime?(num)
p = false
i = num
while !p
i += 2
p = prime?(i)
end
new_arr << i
The only infinite loop I encounter is when you hit 2 in the second array, because to check for primes, you just keep incrementing by 2, and so you end up checking every multiple of 2 to see if it's prime. Naturally you never find a prime multiple of 2. To fix this, instead of incrementing by 2 before checking for the next prime, if you increment by 1 would work, you just need to check twice as many numbers:
if prime?(num)
p = false
i = num
while !p
i += 1
p = prime?(i)
end
new_arr << i
your last problem is that your prime? function returns false for 3, which can be fixed by changing:
elsif num <= 3
return true
and now your 2 samples yield:
[11, 13, 17, 23] => [13, 17, 19, 29]
[11, 8, 2, 24] => [13, 8, 3, 24]
Similar to #Cary Swoveland answer, but more idiomatic Ruby IMHO.
require 'prime'
def next_primes(ary)
ary.map { |candidate| candidate.prime? ? next_prime(candidate) : candidate }
end
def next_prime(previous_prime)
all_primes = Prime.each
all_primes.find { |prime| prime > previous_prime }
end
next_primes([11,8,2,24]) # => [13, 8, 3, 24]
next_primes([11,13,17,23]) # => [13, 17, 19, 29]
I've assumed the array arr is sorted. If it isn't, save the original indices of the sorted values, which are then used to reorder the elements of the array of values containing prime and non-prime numbers. For example, if
arr = [57, 13, 28, 6]
then
indices = arr.each_with_index.sort.map(&:last)
#=> [3, 1, 2 0]
The steps of the the main method are as follows.
Step 1: create an empty array a that will be returned by the method.
Step 2: create an enumerator, enum, that generates an infinite sequence of prime numbers (2, 3, 5, 7,..). Generate the first prime m = enum.next #=> 2.
Step 3: create an enumerator, earr, that generate the elements of the given array arr.
Step 4: consider the next element of the array, x = earr.next, which is initially the first element of the array. When there are no more elements of the array, break from the loop and return the array a.
Step 5: if x is not prime save it to an array a (a << x) and repeat step 4; else go to Step 6.
Step 6: (x is prime) if x < m, save m to the array a and go to
Step 4; else (i.e., m <= x), obtain the next prime (m = enum.next) and repeat this step.
require 'prime"
def next_primes(arr)
enum = Prime.each
m = enum.next
earr = arr.to_enum
x = earr.next
a = []
loop do
if x.prime?
if x < m
a << m
x = earr.next
else
m = enum.next
end
else
a << x
x = earr.next
end
end
a
end
next_primes([2, 6, 7, 23, 100])
#=> [3, 6, 11, 29, 100]
next_primes([2, 6, 7, 7, 100])
#=> [3, 6, 11, 11, 100]
Solution to find the next prime number if it is a prime number if not return the same number:
def is_prime(num)
if num<2
return false
end
(2...num).each do |i|
if num%i == 0
return false
end
end
return true
end
def next_prime(arr)
new_arr = []
arr.each do |num|
if is_prime(num)
p = false
i = num
while !p
i += 1
p = is_prime(i)
end
new_arr<<i
else
new_arr<<num
end
end
return new_arr
end
print next_prime([2,3,4,5])
puts
print next_prime([2, 6, 7, 23, 100]) #[3, 6, 11, 29, 100]
In my code below it seems that the i variable in the 2nd while loop is not incrementing within the 2nd while loop, but it is incrementing in the first while loop. So i is always equal to zero in the 2nd while loop, however I need it to increment +1 each pass.
Here is my code:
# Code required to read in the values of k,n and candies.
n = gets.to_i
k = gets.to_i
candy = Array.new(n)
for i in 0..n-1
candy[i] = gets.to_i
end
#create loop to calculate max-min and compare to lowest max-min value calculated thus far.
arr = []
i = 0
candy = candy.sort
ans = nil
#iterate through candy array to create n minus k sub-arrays of size k
while i < n-k
m = 0
#create sub-array of size k
while m < k
arr << candy[i + m].to_i
m += 1
end
#find the difference between the max and the min value in the sub-array
arrcheck = (arr[k-1]) - (arr[0])
i += 1
#if ans is nil set the ans variable to arrcheck, else if arrcheck is less than the ans set ans to arrcheck
if ans == nil
ans = arrcheck
elsif arrcheck < ans
ans = arrcheck
end
end
### Compute answer from k, n, candies
puts ans
Since the i in the 2nd loop is not incrementing it is just checking the same sub-array n minus k times without advancing through the entire candy array.
I see two mistakes in your code:
while i < n - k should be while i <= n - k
arr = [] must be moved into the while loop
Fixed code:
while i <= n - k
m = 0
arr = []
# ...
Although your code works with the above fix, it's not very idiomatic. I'd write something like:
print 'number of candies: '
n = gets.to_i
print 'sub-array size: '
k = gets.to_i
candies = []
(1..n).each do |i|
print "candy #{i}: "
candies << gets.to_i
end
puts candies.sort.each_cons(k).map { |a| a.last - a.first }.min
Let's examine the last line:
candies = [1, 7, 10, 2]
k = 2
candies #=> [1, 7, 10, 2]
.sort #=> [1, 2, 7, 10]
.each_cons(k) #=> [[1, 2], [2, 7], [7, 10]]
.map { |a| a.last - a.first } #=> [1, 5, 3]
.min #=> 1
I've been going at this problem for a few hours, and I can't see why I can't get it to run properly. The end game to this method is having 2 numbers in an array equaling zero when added together. Here is my code:
def two_sums(nums)
i = 0
j = -1
while i < nums.count
num_1 = nums[i]
while j < nums.count
num_2 = nums[j]
if num_1 + num_2 == 0
return "There are 2 numbers that sum to zero & they are #{num_1} and #{num_2}."
else
return "Nothing adds to zero."
end
end
i += 1
j -= 1
end
end
The problem I'm having is unless the first and last number in the array are the positive and negative of the same number, this will always return false.
For example, if I had an array that was [1, 4, 6, -1, 10], it should come back true. I'm sure my 2 while statement is the cause of this, but I can't think of a way to fix it. If someone could point me in the right direction, that would be helpful.
You can find the first pair that adds up to 0 like this:
nums.combination(2).find { |x, y| x + y == 0 }
#=> returns the first matching pair or nil
Or if you want to select all pairs that add up to 0:
nums.combination(2).select { |x, y| x + y == 0 }
#=> returns all matching pairs or an empty array
Therefore you can implement your method like this:
def two_sums(nums)
pair = nums.combination(2).find { |x, y| x + y == 0 }
if pair
"There are 2 numbers that sum to zero & they are #{pair.first} and #{pair.last}."
else
"Nothing adds to zero."
end
end
Or if you want to find all pairs:
def two_sums(nums)
pairs = nums.combination(2).select { |x, y| x + y == 0 }
if pairs.empty?
"Nothing adds to zero."
else
"The following pairs sum to zero: #{pairs}..."
end
end
Here's another way:
Code
def sum_to_zero(arr)
arr.group_by { |e| e.abs }
.values
.select { |a| (a.size > 1 && a.first == 0) || a.uniq.size > 1 }
end
Examples
sum_to_zero [1, 4, 6, -1, 10] #=> [[1, -1]]
sum_to_zero [1, 4, 1, -2, 10] #=> []
sum_to_zero [1, 0, 4, 1, 0, -1] #=> [[1, 1, -1], [0, 0]]
This method is relatively fast. Let's try it with an array of 200,000 elements, each a random number between -500,000 and 500,000.
require 'time'
t = Time.now
arr = Array.new(200_000) { rand(1_000_001) - 500_000 }
arr.size #=> 200000
sum_to_zero(arr).size #=> 16439
Time.now - t
#=> 0.23 (seconds)
sum_to_zero(arr).first(6)
#=> [[-98747, 98747],
# [157848, -157848],
# [-459650, 459650],
# [176655, 176655, -176655],
# [282101, -282101],
# [100886, 100886, -100886]]
If you wish to group the non-negative and negative values that sum to zero:
sum_to_zero(arr).map { |a| a.partition { |e| e >= 0 } }.first(6)
#=> [[[98747], [-98747]],
# [[157848], [-157848]],
# [[459650], [-459650]],
# [[176655, 176655], [-176655]],
# [[282101], [-282101]],
# [[100886, 100886], [-100886]]]
If you only want a single value for each group (a non-negative value, say):
sum_to_zero(arr).map { |a| a.first.abs }.first(6)
#=> [98747, 157848, 459650, 176655, 282101, 100886]
I think the most Ruby way would be:
nums.combination(2).any? { |x,y| (x+y).zero? }
Here's a way that should work well for large arrays. The methods above which go through every possible combination of two numbers are perfectly fine for small cases but will be very slow and memory hungry for arrays with lots of elements.
def two_sums nums
h = Hash.new
nums.each do |n|
return true if h[-n]
h[n] = true
end
false
end
Well, given it's tagged as #ruby, here's the most "ruby way" I could think of tackling this problem:
def two_sums(arr)
numbers = arr.combination(2).select { |a| a.reduce(:+) == 0 }.flatten
if numbers.empty?
"Nothing adds to zero."
else
"There are 2 numbers that sum to zero & they are #{numbers.first} and #{numbers.last}."
end
end
array.combination(2).select{|x|x[0] + x[1] == 0}