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

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

Related

How not get out of bound in Kotlin?

I got the code that compare current element with the next element in array. But it crashes with out of bound because I guess when its on the last element there is no next element to compare with so it crashes.How to handle this to avoid crash and stop comparing on the last element? Here is my code
fun myFunction(arr: Array<Int>): Int{
if (arr.isEmpty()) return 0
var result = 0
for (item in arr.indices) {
if (arr[item] > 0 && arr[item + 1] < 0){
result ++
}
if (arr[item] < 0 && arr[item + 1] > 0){
result ++
}
}
return result
}
The direct answer to your question:
Instead of
for (item in arr.indices)
you should write
for (item in 0..(arr.lastIndex - 1))
Explanation: arr.indices returns the range 0..arr.lastIndex but in the loop you are checking the element after the current index; therefore you should only go up to arr.lastIndex - 1.
Some further advice:
IntArray is more efficient than Array<Int>
You can combine the two if statements into one using the || (or) operator.
If you are counting the number of sign changes, you need to consider how to interpret 0. In your code, an input of [1,-1] would give a result of 1 sign change, but [1,0,-1] would give 0, which seems wrong. To fix that, treat 0 as positive:
if ((arr[item] >= 0 && arr[item + 1] < 0) || arr[item] < 0 && arr[item + 1] >= 0) {
result++
}
You don't need to check if the array is empty; just remove that line. The loop won't be entered if the array is empty or if it has only 1 element.
Finally, you can use some cool features of the standard libray (look them up in the documentation to learn them) which can make your function succinct:
fun myFunction(arr: IntArray): Int {
var result = 0
arr.asList().zipWithNext().forEach { (a, b) ->
if ((a >= 0 && b < 0) || (a < 0 && b >= 0))
result++
}
return result
}
and even more succinct still:
fun myFunction(arr: IntArray) =
arr.asList().zipWithNext().count { (a, b) -> (a >= 0) != (b >= 0) }
References: single-expression functions, zipWithNext, count, destructuring.

What is wrong with my LongestMatrixPath ruby algorithm?

Using the Ruby language, have the function LongestMatrixPath(strArr) take the array of strings stored in strArr, which will be an NxM matrix of positive single-digit integers, and find the longest increasing path composed of distinct integers. When moving through the matrix, you can only go up, down, left, and right. For example: if strArr is ["345", "326", "221"], then this looks like the following matrix:
3 4 5
3 2 6
2 2 1
For the input above, the longest increasing path goes from: 3 -> 4 -> 5 -> 6. Your program should return the number of connections in the longest path, so therefore for this input your program should return 3. There may not necessarily always be a longest path within the matrix.
def recursiveFunction(array, row, col, path)
current = array[row][col]
row-1 >= 0 ? up = array[row-1][col] : up = nil
row+1 < array.length ? down = array[row+1][col] : down = nil
col-1 >= 0 ? left = array[row][col-1] : left = nil
col+1 < array[row].length ? right = array[row][col+1] : right =
nil
if !path.include?(current) && current.to_i > path[-1].to_i
path.push(current)
p path
if up && up.to_i > current.to_i
recursiveFunction(array, (row-1), col, path)
elsif down && down.to_i > current.to_i
recursiveFunction(array, (row+1), col, path)
elsif left && left.to_i > current.to_i
recursiveFunction(array, row, (col-1), path)
elsif right && right.to_i > current.to_i
recursiveFunction(array, row, (col+1), path)
end
end
path
end
def LongestMatrixPath(strArr)
# turn each string into an array
strArr.map!{|str| str.split("")}
# calculate up, down, left, right formula
# up = [-1][same]
# down = [+2][same]
# left = [same][-1]
# right = [same][+1]
# create data structure to store paths
path = []
# create loop that loops through each element in each array
inside strArr
# then apply recursive function to each element
longest_path = 0
row = 0
while row < strArr.length
col = 0
while col < strArr[row].length
result = recursiveFunction(strArr, row, col, path=[])
longest_path = result.length if result.length > longest_path
col += 1
end
row += 1
end
# return number of connections
result.length-1
end
# LongestMatrixPath(["345", "326", "221"])
# correct answer: 3, my answer: 3
# LongestMatrixPath(["12256", "56219", "43215"])
# correct answer: 4, my answer: 3
# LongestMatrixPath(["67", "21", "45"])
# correct answer: 3, my answer: 1
# LongestMatrixPath(["111", "111", "111"])
# correct answer: 0, my answer: 0
# LongestMatrixPath(["123", "456", "789"])
# correct answer: 4, my answer: 4
The problem exists in this fragment:
if up && up.to_i > current.to_i
recursiveFunction(array, (row-1), col, path)
elsif down && down.to_i > current.to_i
recursiveFunction(array, (row+1), col, path)
elsif left && left.to_i > current.to_i
recursiveFunction(array, row, (col-1), path)
elsif right && right.to_i > current.to_i
recursiveFunction(array, row, (col+1), path)
end
Here, if up is larger than current and, for example, left is also larger than current, you only go up (because of elsif). Instead, you need to go in all possible directions and choose most "promising" one. I altered your code a bit to achieve that, trying to change as little as possible. This works, but might not be the best option though.
def recursiveFunction(array, row, col, original_path)
current = array[row][col]
row-1 >= 0 ? up = array[row-1][col] : up = nil
row+1 < array.length ? down = array[row+1][col] : down = nil
col-1 >= 0 ? left = array[row][col-1] : left = nil
col+1 < array[row].length ? right = array[row][col+1] : right =
nil
path = original_path.dup
if !path.include?(current) && current.to_i > path[-1].to_i
path.push(current)
# p path
options = []
if up && up.to_i > current.to_i
options << recursiveFunction(array, (row-1), col, path)
end
if down && down.to_i > current.to_i
options << recursiveFunction(array, (row+1), col, path)
end
if left && left.to_i > current.to_i
options << recursiveFunction(array, row, (col-1), path)
end
if right && right.to_i > current.to_i
options << recursiveFunction(array, row, (col+1), path)
end
best_path = options.sort_by{ |p| p.length }.last
path += best_path.drop(path.length) if best_path
end
path
end
Not a couple of thing here:
Instead modifying path parameter given into function, it gets duplicated, so you can work on it in many steps.
All conditions for up, down, left and right are checked now. The results are put into an array and then the best result (in terms of length) is chosen.
Then the remainder of this longest path is appended to path with path += best_path.drop(path.length) (if exists)
The results for examples you gave are correct, except example two, where correct answer is 5, not 4.
There is much more that can be improved in this code though. For example, you can do strArr.map!{|str| str.split("").map(&:to_i)} and get rid of all those .to_i in the code.

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

Algorithm to check matching parenthesis

This relates to the Coursera Scala course so I want to directly ask you NOT to give me the answer to the problem, but rather to help me debug why something is happening, as a direct answer would violate the Coursera honor code.
I have the following code:
def balance(chars: List[Char]): Boolean = {
val x = 0
def loop(list: List[Char]): Boolean = {
println(list)
if (list.isEmpty) if(x == 0) true
else if (list.head == '(') pushToStack(list.tail)
else if (list.head == ')') if(x <= 0) false else decreaseStack(list.tail)
else loop(list.tail)
true
}
def pushToStack(myList: List[Char]) { x + 1; loop(myList)}
def decreaseStack(myList: List[Char]) { x - 1; loop(myList)}
loop(chars)
}
A simple explanation:
If the code sees a "(" then it adds 1 to a variable. If it sees a ")" then it first checks whether the variable is equal to or smaller than 0. If this is the case, it returns false. If the value is bigger than 0 then it simply decreases one from the variable.
I have tried running the following:
if(balance("This is surely bad :-( ) (".toList)) println("balanced") else println("not balanced");
Clearly this is not balanced, but my code is returning balanced.
Again: I am not asking for help in writing this program, but rather help in explained why the code is returning "balanced" when clearly the string is not balanced
--EDIT--
def balance(chars: List[Char]): Boolean = {
val temp = 0;
def loop(list: List[Char], number: Int): Boolean = {
println(list)
if (list.isEmpty) if(number == 0) true
else if (list.head == '(') loop(list.tail, number + 1)
else if (list.head == ')') if(number <= 0) false else loop(list.tail, number - 1)
else loop(list.tail,number)
true
}
loop(chars,0)
}
^^ Still prints out balanced
You are using an immutable x when you really want a mutable x.
Here, let me rewrite it for you in a tail recursive style to show you what you're actually doing:
#tailrec def loop(myList: List[Char], cur: Int = 0): Boolean = myList match{
case "(" :: xs =>
val tempINeverUse = cur+1
loop(xs, cur) //I passed in 0 without ever changing "cur"!
case ")" :: xs if cur < 0 => false //This is a bug, regardless if you fix the rest of it
case ")" :: xs =>
val tempINeverUse = cur-1
loop(xs, cur) //Passed in 0 again!
case x :: xs => loop(xs, cur)
case Nil => cur == 0 //Since I've never changed it, it will be 0.
}
You need to keep a context of parenthesis in comments or in quotes as well. You can use a counter to achieve that. If the counter is set for a comment or a double quote then ignore any parenthesis that comes your way. Reset the counter whenever you find a finishing comment or double quote

Looping in an array to attain nearest larger integer

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.

Resources