Given an array, replace each prime number with the next prime number - ruby

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]

Related

in an array, Count the Positives and give the Sum of Negatives in Ruby

The question says:
Given an array of integers.
Return an array, where the first element is the count of positives numbers and the second element is sum of negative numbers. 0 is neither positive nor negative.
If the input is an empty array or is null, return an empty array.
def count_positives_sum_negatives(last)
pos = []
neg = []
x = lst.each
if x % 2 == 0
pos.push x
else neg.push x
end
y = pos.count
z = neg.sum
puts "[#{y},#{z}]"
end
I tested with
count_positives_sum_negatives([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15])
#should return [10, -65]
I am unsure why my one only gives an error message:
An error occurred while loading spec_helper.
Failure/Error: if (x % 2) == 0
NoMethodError:
undefined method `%' for #<Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15]:each>
# ./lib/solution.rb:7:in `count_positives_sum_negatives'
# ./lib/solution.rb:18:in `<top (required)>'
# ./spec/spec_helper.rb:1:in `require'
# ./spec/spec_helper.rb:1:in `<top (required)>'
No examples found.
No examples found.
You also certainly meant lst.each do |x| rather than x = lst.each. You get the error you do because lst.each without a block returns an Enumerator object, and that does not respond to %.
def count_positives_sum_negatives(lst)
pos = []
neg = []
lst.each do |x|
if x % 2 == 0
pos.push x
else
neg.push x
end
end
y = pos.count
z = neg.sum
puts "[#{y},#{z}]"
end
Note: x % 2 == 0 can be written as x.even?
But you're looking at evens and odds, and your description says count positives and sum negatives. You can use #positive? and #negative? for this, along with #partition.
def count_positives_sum_negatives(lst)
pos, neg = lst.partition(&:positive?)
y = pos.count
z = neg.sum
puts "[#{y},#{z}]"
end
You could also use #each_with_object to give you the info you're looking for.
def count_positives_sum_negatives(lst)
lst.each_with_object([0, 0]) do |x, arr|
if x.positive?
arr[0] += 1
else
arr[1] += x
end
end
end
#Chris has given the reason for your problem.
I think I would be inclined to write it as follows.
def count_positives_sum_negatives(lst)
non_pos = lst.reject(&:positive?)
[lst.size - non_pos.size, non_pos.sum]
end
count_positives_sum_negatives [-1, 2, 0, 0, 1, -4, -7, 0, 6]
#=> [3, -12]
This has the weakness that a temporary array is created (non_pos), but lst.size - non_pos.size and non_pos.sum are both relatively fast calculations, the latter because it is implemented in C. One would have to benchmark, however.
lst.reject(&:positive?) is a short form of lst.reject { |n| n.positive? ).
See Array#reject and Array#sum.
Okay, this final one I've done outputs the correct answer, but I think the portal itself is broken as it cannot tell that [10, -65] is the same as [10, -65]
enter image description here
def count_positives_sum_negatives(lst)
pos = []
neg = []
lst.each do |x|
if x.positive?
pos.push x
else
neg.push x
end
end
y = pos.count
z = neg.sum
final = []
final << y
final << z
print final
end

Ruby array five_sort algorithm

I'm trying to solve a problem called five_sort that accepts an array of integers as the argument and places all the fives at the end of the array and leaves all of the other numbers unsorted. For example, [1,2,5,3,2,5,5,7] would be sorted as [1,2,3,2,7,5,5,5].The rules for the problem state that only a while loops can be used and no other methods can be called on the array except [] and []=. Here is my current code:
def five_sort(array)
sorted = false
while sorted == false
idx = 0
while idx < array.length
if array[idx] == 5
array[idx], array[idx + 1] = array[idx + 1], array[idx]
end
idx += 1
end
sorted = true
end
array
end
When running it, it is just in a continuous loop but I can't find out how to fix it. I know that if I just run the second while loop without the while sorted loop, the array would only run once and the fives would only switch places once and the loop would be over. But I don't know how to run the second while loop and stop it once all the fives are at the end.
Can anyone help me figure this one out?
Just a simple O(n) time and O(1) space solution, using a write-index and a read-index.
w = r = 0
while array[w]
r += 1 while array[r] == 5
array[w] = array[r] || 5
w += 1
r += 1
end
While a couple of people have posted alternative approaches, which are all good, I wanted to post something based on your own code to reassure you that you had got pretty close to a solution.
I've added comments to explain the changes I've made:
def five_sort(array)
sorted = false
while sorted == false
idx = 0
# use did_swap to keep track of if we've needed to swap any numbers
did_swap = false
# check if next element is nil as alternative to using Array#length
while array[idx + 1] != nil
# it's only really a swap if the other entry is not also a 5
if array[idx] == 5 and array[idx + 1] != 5
array[idx], array[idx + 1] = array[idx + 1], array[idx]
did_swap = true
end
idx += 1
end
# if we've been through the array without needing to make any swaps
# then the list is sorted
if !did_swap
sorted = true
end
end
array
end
Your array is becoming longer at each loop:
array = [1,2]
array[1], array[2] = array[2], array[1]
puts array.length
Outputs 3.
What you need is to not swap if idx = array.length - 1
if (array[idx] == 5)
array[idx], array[idx+1] = array[idx+1], array[idx] if idx != array.length - 1
end
def five_sort(arr)
i = 0
cnt = 0
while arr[i]
if arr[i] == 5 && arr[i+1]
arr[i..i] = []
cnt += 1
else
i += 1
end
end
cnt.times { arr[-1,2] = [arr[-1],5] }
arr
end
arr = [1,5,3,5,6]
five_sort arr
#=> [1, 3, 6, 5, 5]
arr
#=> [1, 3, 6, 5, 5] # confirms arr is mutated
five_sort [5,5,5,3,6]
#=> [3, 6, 5, 5, 5]
five_sort [5,5,5,5,5]
#=> [5, 5, 5, 5, 5]
five_sort [1,2,3,4,6]
#=> [1, 2, 3, 4, 6]
five_sort []
#=> []
Notes:
As required by the spec, the only methods invoked on arr are [] and []= and no other arrays are created.
if i indexes the last element of the array, arr[i+1] equals nil.
arr[i..i] = [] removes the elementarr[i] from arr.
arr[-1,2] = [arr[-1],5] appends a 5 to arr.

How to iterate through array using nested while loops in Ruby?

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

Checking to see if 2 numbers in array sum to 0 in Ruby

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}

Get total number of ranges of a given length in an array

I have an array total of 12 elements, each element represents and int. For instance total[0] = 1. I have another array remaining that is total - occupied spaces. remaining will have fewer elements that total.
I want to write a method that can look in total for instances where there are >= size gaps between consecutive ints in the array. For example:
If `foo.total = [1,2,6,7,8,9,]`
then when I call `foo.number_of_slots_available(3)`
I get `2` (because 3,4,5 is not included and 10,11,12 is not included)
Here are the beginnings of my method:
def number_of_slots(size)
total_array = (1..12).to_a
occupied_spaces = some_map.to_a
remaining_array = total_array - occupied_spaces
return ????
end
Enumerable#chunk is the good way to go. Look below.
arr = [1,2,6,7,8,9]
rng = (1..12).to_a
rng.chunk { |i| arr.include? i }.to_a
# => [[true, [1, 2]],
# [false, [3, 4, 5]],
# [true, [6, 7, 8, 9]],
# [false, [10, 11, 12]]]
rng.chunk { |i| arr.include? i }.count{|j| j[0] == false}
# => 2
Edit
"I want to write a method that can look in total for instances where there are >= size gaps between consecutive ints in the array"
arr = [1,2,3,6,7,8,9,10,11]
rng = (1..15).to_a
rng.chunk { |i| arr.include? i }.to_a
# => [[true, [1, 2, 3]],
# [false, [4, 5]],
# [true, [6, 7, 8, 9, 10, 11]],
# [false, [12, 13, 14, 15]]]
rng.chunk { |i| arr.include? i }.count{|j| j[0] == false and j[1].size >= 3 }
# => 1
rng.chunk { |i| arr.include? i }.count{|j| j[0] == false and j[1].size >= 2 }
# => 2
# J[1] is the array,whose size is the actual gap size.
If total is sorted is a simple algorithm and should be something like this (I might have some syntax errors):
def containsGaps(total, gap)
int i = 0;
int count = 0;
while i < total.length -1 do
if total[i+1] - total[i] >= gap then count++;
end
return count;
end
And your return might be:
return containsGaps(total_array, size);
Here is a way I found of doing it. I modified the method a bit adding in the array to be passed along with the size.
#!/usr/bin/ruby
arr = [1,2,6,7,8,9]
bar = [1,2,3,6,7,10]
def number_of_slots(arr, size)
count = 0
range = (1..12).to_a
# arr.sort! (if the array is not always sorted)
range.each_cons(size) do |chunk|
if (chunk & arr).size == 0
count += 1
end
end
count
end
puts number_of_slots(arr, 3)
puts number_of_slots(bar, 2)
Output:
2
3

Resources