Looping in an array to attain nearest larger integer - ruby

Below is my code to solve the following problem:
Write a function, nearest_larger(arr, i) which takes an array and an
index. The function should return another index, j: this should
satisfy:
(a) arr[i] < arr[j], AND
(b) there is no j2 closer to i than j where arr[i] < arr[j].
In case of ties choose the earliest (left-most)
of the two indices. If no number in arr is larger than arr[i],
return nil.
This was my attempt:
def nearest_larger(arr, i)
k = 1
loop do
jleft = i - k
jright = i + k
if (arr[i] < arr[jleft]) && (jleft >= 0)
return jleft
elsif (arr[i] < arr[jright]) && (jright < arr.length)
return jright
elsif (jleft < 0) && (jright >= arr.length)
return nil
end
k += 1
end
end
This is the actual correct answer
def nearest_larger(arr, idx)
diff = 1
loop do
left = idx - diff
right = idx + diff
if (left >= 0) && (arr[left] > arr[idx])
return left
elsif (right < arr.length) && (arr[right] > arr[idx])
return right
elsif (left < 0) && (right >= arr.length)
return nil
end
diff += 1
end
end
While my code works well for many of the values I tested when I use certain combinations like this:
x = [1,6,9,4,5]
puts nealest_larger(x, 4)
I get this error
calc.rb:8:in `<': comparison of Fixnum with nil failed (ArgumentError)
from calc.rb:8:in `block in nealest_larger'
from calc.rb:3:in `loop'
from calc.rb:3:in `nealest_larger'
from calc.rb:40:in `<main>'
Can someone tell me how my code differs from the actual answer, to me it seems like it should behave exactly the same but I must have missed some syntax or overlooked a piece of logic. I need another pair of eyes as I am unable to see the difference, thanks!

Your version uses array indices before you've checked that they're in-bounds, i.e., on the left-hand side of the &&. The working version checks for in-bounds first, then uses the index if it's legal. Because Ruby && short circuits, test && use approach avoids the problem you ran into with your implementation.

The 8th line of code in your solution compares the values in the array before first checking the bounds of the array. Notice the correct solution does those comparisons in the reverse order, and the && operator short circuits, avoiding the second (invalid) comparison.

Related

z3 ruby How create array and get only some element

I create array but cant select element.
I need array/vector with exactli this same element
[ [0,0,0] , [1,1,1] ...]
require "z3"
A = Array.new(3){|x| Z3.Int("x#{x}") }
i = Z3.Int("i")
j = Z3.Int("j")
r = Z3::Solver.new
r.assert i >= 0 && i <= 2
r.assert j >= 0 && j <= 2
r.assert r.Select(A,i) == r.Select(A,j)
r.check
p r.model
First, there's a minor syntax issue with &&. Ruby does not allow overloading of &&, so Z3 expressions need to use & and some extra parentheses:
r.assert (i >= 0) & (i <= 2)
A much bigger issue is conceptual. Do you want to use Z3 Arrays, or just plain Ruby array of Z3 Integers.
If you use Z3 arrays, then what you're asking is that some i and j exist, for which a[i] == a[j]:
require "z3"
Z3IntIntArray = Z3::ArraySort.new(Z3::IntSort.new, Z3::IntSort.new)
a = Z3IntIntArray.var("x")
i = Z3.Int("i")
j = Z3.Int("j")
r = Z3::Solver.new
r.assert (i >= 0) & (i <= 2)
r.assert (j >= 0) & (j <= 2)
r.assert a.select(i) == a.select(j)
r.check
p r.model
(upgrade to latest gem for this snippet to work)
But this could be satisfied by a model like a=[42,0,100,550], i=2, j=2.
If I run it, this returns:
Z3::Model<i=0, j=2, x=const(3)>
That is infinitely big array of all 3s, and some arbitrary i and j values. Z3 usually picks the simplest answer if it has multiple possibilities, but it could easily pick something where x[1] is a different number, as you're not really asserting anything about it.
If you use plain Ruby objects, you can specify all equalities:
require "z3"
a = (0..2).map{|i| Z3.Int("a#{i}") }
r = Z3::Solver.new
(0..2).each do |i|
(0..2).each do |j|
r.assert a[i] == a[j]
end
end
r.check
p r.model
You can save yourself O(N^2) code and just check that a[0] == a[1], a[1] == a[2] etc.:
require "z3"
a = (0..2).map{|i| Z3.Int("a#{i}") }
r = Z3::Solver.new
a.each_cons(2) do |ai, aj|
r.assert ai == aj
end
r.check
p r.model
Either of these returns:
Z3::Model<a0=0, a1=0, a2=0>

Binary Search error when doesn't find a number

I've created a binary search, while looking at the online wiki. I have a class of Athletes that each have a name and number. I'm inputting a file text or csv, doesn't matter - with each of the athletes name's and numbers. My program sorts them first, and then I am trying to add the functionality of searching for a number based off of user input, and displaying who wears that numbered jersey. So my initial post was trying to binary search for people with the same number. As in, if I had Michael Jordan and Lebron James on my list, they both wear 23 - so when my search goes through it would only output 1 (whichever it comes to first). I was looking for how to make my search (below) accept/find multiple occurrences of a number. However, upon further testing, I found that if I input a number not actually in my list it would give me the error: search: stack level too deep which I don't know what that means. I think my search doesn't handle properly if there's no instance of the number, or if the array is 0.
So I was looking for some help to see how I can fix this to work if the number input by a user isn't in the list. So if someone inputs "1000" -- no one has worn that jersey number and should return false. Or something of that sort, break, whatever.
def search(array, num, start = 0, last = nil)
if last == nil
last = array.count - 1
end
mid = (start + last) / 2
if num < array[mid].number
return search(array, num, start, mid - 1)
elsif num > array[mid].number
return search(array, num, mid + 1, last)
else
return mid
end
end
I've now also gotten ==: stack level too deep on the line where if last == nil
This is not the ruby way of doing things. When you have a collection, and you would like to only select some of them based on a certain condition, The ruby approach would be to use Enumerable#select
You would ideally have some array of athletes like so
athletes = [Athlete.new, Athlete.new]
athletes_with_number_23 = athletes.select { |athlete| athlete.number == 23 } #if you want all
first_athlete_wearing_23 = athletes.detect { |athlete| athlete.number == 23 } #if you want only the first one
Disclaimer: this is pseudo code.
I changed my search function:
def search(array, key)
lo = 0
hi = array.length-1
while(lo <= hi)
mid = lo + ((hi-lo)/2)
if array[mid].number == key
return mid
elsif array[mid].number < key
lo = mid + 1
else
hi = mid - 1
end
end
puts "Value not found in array"
end
If I got u right you wanna get ALL athletes with a specific number in a sorted list.
First. Your code is a way too procedural, "This is not the ruby way of doing things.". But I guess it doesn't matter for you.
So, I suggest you find an index of one of the athletes and just walk array left and right from it to collect same-number mans.
Here my procedural version. It uses your function.
def athletes_with_number(athletes, number)
result = []
found_index = search(athletes, number)
return result unless found_index
# walk left
i = found_index
while i >= 0 && athletes[i].number == number
result << athletes[i]
i -= 1
end
# walk right
i = found_index + 1 # athletes[found_index] already added
while i < athletes.size && athletes[i].number == number
result << athletes[i]
i += 1
end
result
end
def search(array, key)
lo = 0
hi = array.length-1
while(lo <= hi)
mid = lo + ((hi-lo)/2)
if array[mid].number == key
return mid
elsif array[mid].number < key
lo = mid + 1
else
hi = mid - 1
end
end
nil
end

Arithmetic/Geometric series

The code below returns "Arithmetic", "Geometric" if the input array is an arithmetic and geometric series respectively and -1 if it is neither.
Although the code works fine, when I change
if s = arr.length - 1
to
if s == arr.length - 1
in the while loop, the code is not working properly anymore.
I do not understand why. Shouldn't == work instead of =?
def ArithGeo(arr)
# code goes here
len = arr.length
difference = arr[len-1] - arr[len-2]
ratio = arr[len-1]/arr[len-2]
k = 0
s = k + 1
while (arr[s] - arr[k]) == difference && s < arr.length
if s = arr.length - 1
return "Arithmetic"
end
k += 1
end
k = 0
while arr[s] / arr[k] == ratio && s < arr.length
if s = arr.length - 1
return "Geometric"
end
k += 1
end
return -1
end
You're never changing the value of s which I think you want to do. You should do that at the point that you increment k
k += 1
s = k + 1
Also, at the point where you reinitialize k for the geometric test, you want to reset s as well...
k = 0
s = k + 1
You could also get rid of the variable s completely and make it a method... add these three lines at the top of the code
def s(k)
k + 1
end
And remove all the lines where you assign a value to s and use s(k)... s(k) will be a method that always returns the next higher value to k
The difference between those two statements is that variable s is set for the first statement but not for the second. The first if statement has thus a side effect of setting s to arr.length - 1
if s = arr.length - 1 # s => arr.length - 1
if s == arr.length - 1 # s => undefined
Because the if statement is inside a while loop which uses s in its expression the change of the statement changes the behavior of the programm.
If you put == the statement will try to check if they are equals , with just = the statement work properly because your are only setting the value to a value , so this is always true.
If it's different compare something to equals than just set a variable , that can be always true.

Bignum too big to convert into 'long' (RangeError)

Trying to teach myself ruby - I'm working on Project Euler problem 14 in ruby.
n = 1000000
array = Array.new(n,0)
#array[x] will store the number of steps to get to one if a solution has been found and 0 otherwise. x will equal the starting number. array[0] will be nonsensical for these purposes
i = n-1#We will start at array[n-1] and work down to 1
while i > 1
if array[i] == 0
numstep = 0 #numstep will hold the number of loops that j makes until it gets to 1 or a number that has already been solved
j = i
while j > 1 && (array[j] == 0 || array[j] == nil)
case j%2
when 1 # j is odd
j = 3*j + 1
when 0 # j is even
j = j/2
end
numstep += 1
end
stop = array[j] #if j has been solved, array[j] is the number of steps to j = 1. If j = 1, array[j] = 0
j = i
counter = 0
while j > 1 && (array[j] == 0 || array[j] == nil)
if j < n
array[j] = numstep + stop - counter #numstep + stop should equal the solution to the ith number, to get the jth number we subtract counter
end
case j%2
when 1 #j is odd
j = 3*j+1
when 0 #j is even
j = j/2
end
counter += 1
end
end
i = i-1
end
puts("The longest Collatz sequence starting below #{n} starts at #{array.each_with_index.max[1]} and is #{array.max} numbers long")
This code works fine for n = 100000 and below, but when I go up to n = 1000000, it runs for a short while (until j = 999167 *3 + 1 = 2997502). When it tries access the 2997502th index of array, it throws the error
in '[]': bignum too big to convert into 'long' (RangeError)
on line 27 (which is the while statement:
while j > 1 && (array[j] == 0 || array[j] == nil)
How can I get this to not throw an error? Checking if the array is zero saves code efficiency because it allows you to not recalculate something that's already been done, but if I remove the and statement, it runs and gives the correct answer. I'm pretty sure that the problem is that the index of an array can't be a bignum, but maybe there's a way to declare my array such that it can be? I don't much care about the answer itself; I've actually already solved this in C# - just trying to learn ruby, so I'd like to know why my code is doing this (if I'm wrong about why) and how to fix it.
The code above runs happily for me for any input that produces output in acceptable time. I believe this is because you might experience problems being on 32bit arch, or like. Anyway, the solution of the problem stated would be simple (unless you might run out of memory, which is another possible glitch.)
Array indices are limited, as is follows from the error you got. Cool, let’s use hash instead!
n = 1000000
array = Hash.new(0)
#array[x] will store the number of steps to get to one if a solution has been found and 0 otherwise. x will equal the starting number. arr
i = n-1#We will start at array[n-1] and work down to 1
while i > 1
if array[i].zero?
numstep = 0 #numstep will hold the number of loops that j makes until it gets to 1 or a number that has already been solved
j = i
while j > 1 && array[j].zero?
case j%2
when 1 # j is odd
j = 3*j + 1
when 0 # j is even
j = j/2
end
numstep += 1
end
stop = array[j] #if j has been solved, array[j] is the number of steps to j = 1. If j = 1, array[j] = 0
j = i
counter = 0
while j > 1 && array[j].zero?
if j < n
array[j] = numstep + stop - counter #numstep + stop should equal the solution to the ith number, to get the jth number we
end
case j%2
when 1 #j is odd
j = 3*j+1
when 0 #j is even
j = j/2
end
counter += 1
end
end
i = i-1
end
puts("Longest Collatz below #{n} ##{array.sort_by(&:first).map(&:last).each_with_index.max[1]} is #{arr
Please note, that since I used the hash with initializer, array[i] can’t become nil, that’s why the check is done for zero values only.

Where is the break point in this ruby "loop do"?

I am having trouble understanding where the breakpoint is in this do loop. How come the code just doesn't keep running?
def nearest_larger(arr, idx)
diff = 1
loop do
left = idx - diff
right = idx + diff
if (left >= 0) && (arr[left] > arr[idx])
return left
elsif (right < arr.length) && (arr[right] > arr[idx])
return right
elsif (left < 0) && (right >= arr.length)
return nil
end
diff += 1
end
end
Because there are return statements.
Presumably at some point one of the conditions is met and the function exits.
A return statement immediately stops a function, and returns the provided value.
the return keyword is going to stop the running block once it's true

Resources