Ruby: undefined method '>' for nil:NilClass (NoMethodError) - ruby

Currently working on a binary search algorithm for Ruby, but am running into an error when comparing the middle array element with n.
Code Below:
def b_search(n, arr)
middle = arr.length / 2
first = 0
last = arr.length - 1
while first <= last
middle = first + last / 2
if arr[middle] == n
return true
elsif arr[middle] > n
last = middle - 1
else
first = middle + 1
end
end
false
end
nums = [1, 2, 3, 4, 5]
target = 4
if b_search(target, nums)
puts "Target Found"
else
puts "Target Not Found"
end
The error evidently happens in the while loop at the
elsif arr[middle] > n
line, but I'm not sure why. Any help would be appreciated.

It occurs because arr[middle] is nil and nil has no method > defined on it.
Consider that
middle = first + last / 2
is equals to
middle = first + (last / 2)
and you probably meant
middle = (first + last) / 2
so use the parentheses because / has a higher precedence

Related

undefined method `<' for nil:NilClass error but no nil exists?

Was wondering why I get the error: "undefined method `<' for nil:NilClass" when compiling. After looking for reasons why, I found that you cannot use [] on an object with nil as a value. This makes sense, but I don't see why my array would contain nil in it. What am I missing?
def binary_search(n, arr)
middle = arr.length #pick middle value
i = 0
j = arr.length - 1
while i <= j
if arr[middle] == n
return true
elsif arr[middle] < n
i = middle + 1
middle = (i + j) / 2
else
j = middle - 1
middle = (i + j) / 2
end
end
false
end
nums = [76,32,50,90,10,8,15,49]
nums.sort
puts nums.inspect
binary_search(50, nums)
Let's look at a simplified subset of the code:
arr = [76,32,50,90,10,8,15,49]
middle = arr.length # 8
arr[middle] < 50 # NoMethodError
The length is 8.
arr[8] is nil, because there is no item at index 8. Remember that Ruby indexes begin with 0.
nil < 50 is a NoMethodError

Finding the sum of all the numbers between a and b: Ruby

Been working on this Kata for quite some time now and still can't figure out what I'm missing. The question is given two integers a and b, which can be positive or negative, find the sum of all the numbers between including them too and return it. If the two numbers are equal return a or b.
So far this is what my solution looks like:
def get_sum(a,b)
sum = [a+=b].sum
if sum == a or b
return a
end
end
and this is the output result:
Test Passed: Value == 1
Test Passed: Value == 3
Expected: 14, instead got: 4
Expected: 127759, instead got: 509
Expected: 44178, instead got: 444
I believe the keyword is all the numbers between but I'm not sure how to write that syntactically.
I've included some examples below for further clarification.
get_sum(1, 0) == 1 # 1 + 0 = 1
get_sum(1, 2) == 3 # 1 + 2 = 3
get_sum(0, 1) == 1 # 0 + 1 = 1
get_sum(1, 1) == 1 # 1 Since both are same
get_sum(-1, 0) == -1 # -1 + 0 = -1
get_sum(-1, 2) == 2 # -1 + 0 + 1 + 2 = 2
https://www.codewars.com/kata/55f2b110f61eb01779000053/train/ruby
You can use formula for Arithmetic progression:
def get_sum(a, b)
a, b = b, a if a > b
(b - a + 1) * (a + b) / 2
end
Active Support(Rails) extension for Range class OR modern(>= 2.4) Ruby do the same.
So, you can use #MBo answer if your Kata site uses either Rails or modern Ruby. Usually such sites specify the environment and the interpreter version.
def get_sum(a, b)
a, b = b, a if a > b
(a..b).sum
end
Your code does not return result except for a=b case. Also - what [a+=b] generates? Array with a single element a+b, so it's sum is just a+b
Make a range and get it's sum.
Added: parameter ordering
def get_sum(a,b)
a, b = b, a if a > b
return (a..b).sum
end
print get_sum(1,3)
print get_sum(2,2)
print get_sum(-1,2)
print get_sum(3,-1)
>> 6 2 2 5
def get_sum(a,b)
sum = [a+=b].sum
if sum == a or b
return a
end
end
Other answers explain what you could write instead, so let's check your code:
a+=b is called first. It's basically a = a + b, so it calculates the sum of both inputs, saves it in a, and returns a.
sum = [a].sum creates an array with one element, and calculates its sum (which is just this one element). So sum = a
a or b is just a when a is truthy (that is, neither false nor nil).
So here's what your code actually does:
def get_sum(a,b)
a = a + b
sum = a
if sum == a
return a
end
end
Which is just:
def get_sum(a,b)
a = a + b
return a
end
Or :
def get_sum(a,b)
a = a + b
end
or :
def get_sum(a,b)
a + b
end
Please, try with below and ref enter link description here:
def get_sum(a,b)
return a if a == b
return (a..b).sum if b > a
return (b..a).sum if a > b
end
Test:
describe "Example Tests" do
Test.assert_equals(get_sum(1,1),1)
Test.assert_equals(get_sum(0,1),1)
Test.assert_equals(get_sum(0,-1),-1)
Test.assert_equals(get_sum(1,2),3)
Test.assert_equals(get_sum(5,-1),14)
end
Outout:
Test Results:
Example Tests
Test Passed: Value == 1
Test Passed: Value == -1
Test Passed: Value == 3
Test Passed: Value == 14
You have passed all of the tests! :)

recursive binary search in ruby

I've been learning some algorithms and I can't find the reason why my method is failing. if you could look at the code and shed some light as to why that is happening. I would truly appreciate it.
I'm trying to write a method that would binary search an array recursively and so far that is all my code.
def recursive_binary_search(arr, target)
max_index = arr.length - 1
mid_index = max_index / 2
if arr[mid_index] > target
new_arr = arr[0..(mid_index - 1)]
recursive_binary_search(new_arr, target)
elsif arr[mid_index] < target
new_arr = arr[(mid_index + 1)..max_index]
recursive_binary_search(new_arr, target)
else
return mid_index
end
end
The error I keep getting is undefined method '>' for nil:NilClass
I was unable to reproduce the exception reported by the OP (as the data that produced the exception was not given in the question), but the main problem is that, because max_index is computed from arr, and arr is constantly getting smaller, the index returned by the method will have no relation to the correct index in the initial array arr.
Suppose, for example, that arr = [1,2,3,4,5,6] and target = 6. In this case the method will return 0 (rather than 5) as the index of the target element. That's because arr will progressively become arr[3..6], arr[4..6], arr[5..6] and arr[6], at which point index 0 will be returned.
Here is one way the method could be written, using a case statement. The method assumes that target is an element of arr and (as required by binary searches) the elements of arr are ordered, smallest to largest.
def recursive_binary_search(arr, target, min_index=0, max_index=arr.size-1)
mid_index = (min_index+max_index)/2
case arr[mid_index] <=> target
when 0 # arr[mid_index] == target
mid_index
when -1 # arr[mid_index] < target
min_index = mid_index + 1
recursive_binary_search(arr, target, min_index, max_index)
when 1 # arr[mid_index] > target
max_index = mid_index - 1
recursive_binary_search(arr, target, min_index, max_index)
end
end
arr = [1,2,3,4,5,6]
arr.each { |target| puts "#{target}: #{recursive_binary_search(arr, target)}" }
1: 0
2: 1
3: 2
4: 3
5: 4
6: 5
If your arrays are sorted you could try something like this:
def search(arr, target)
return nil if array.empty?
mid_index = array.length / 2
case target <=> array[mid_index]
when -1
search(array.take(mid_index), target)
when 0
mid_index
when 1
subs = search(array.drop(mid_index + 1), target)
subs.nil? ? nil : (mid_index + 1) + subs
end
end

Getting a 'nil:Nil Class' error in Ruby, but the array doesn't seem to empty

I'm trying to code the 'Sieve of Eratosthenes' in Ruby and I'm having difficulty in the second 'while' loop. I want to test to see if integers[j] % integers[0] == 0, but the compiler keeps giving me a nil:Nil Class error at this line. I can't figure out the problem.
n = gets.chomp.to_i
puts
while n < 2
puts 'Please enter an integer >= 2.'
puts
n = gets.chomp.to_i
puts
end
integers = []
i = 0
while i <= n - 3
integers[i] = i + 2
i += 1
end
primes = []
j = 1
while integers != []
primes.push integers[0]
while j <= integers.length
if integers[j] % integers[0] == 0
integers.delete(integers[j])
end
j += 1
end
integers.shift
j = 1
end
puts integers
puts
puts primes
Thanks in advance for any help!
It's an off-by-one error. You're testing for j <= integers.length. So, for example, if you array has five items, the last iteration will be integers[5]. But the last index in a five-item array is 4 (because it starts at 0). You want j < integers.length.

How to Find a Sequence of 4 in an Array with 5 Elements & Fixing Input Error

I've built a Yahtzee game for Ruby Quiz #19. I have the game up and running, however, there are 2 bugs.
When a player chooses to use a roll of >=3 of a kind as a "small straight" (sequence of 4 dice) to "scratch" (score it as zero) that section an error occurs. Here is the code for the small straight:
def sm_straight
#roll = #roll.sort.uniq
if (0..1).any? {|x| (#roll[x+3] - #roll[x+2] == 1) && (#roll[x+2] - #roll[x+1] == 1) && (#roll[x+1] - #roll[x] == 1)}
#scorecard["sm. straight"] = 30
else
puts "Your roll is not a sm. straight! Please select another section or type scratch to score 0 for this section."
scratch = gets.chomp
if scratch == "scratch"
#scorecard["sm. straight"] = "scratch"
elsif #scorecard.has_key?(scratch)
#turn -= 1
section_to_score(scratch)
else
sm_straight
end
end
end
This is the error:
NoMethodError: undefined method -' for nil:NilClass
from Yahtzee_test.rb:209:inblock in sm_straight'
Line 209 is the "if statement" line
When a player incorrectly enters which dice to keep. I am trying to figure out a better way to ask the player how to enter the dice to keep or catch the error and have them re-enter the numbers with the current system. Here is the code"
def roll_again
puts "Which dice would you like to keep from this roll? (1, 2, 3, 4, 5)"
dice_to_keep = gets.chomp.split(',').map {|x| (x.to_i) - 1}.map {|x| #roll[x]}
new_roll = Array.new(5 - dice_to_keep.size) {rand(6) + 1}
#roll = new_roll + dice_to_keep
p #roll
#roll_count += 1
puts "That was roll number #{#roll_count}, you have #{3-#roll_count} remaining."
if #roll_count < 3
more_rolls?
else
section(#roll)
end
end
Any advice on how to write this code better and make it bug free would be greatly appreciated!
To check for a straight of at least 4 out of 5 dice, you could replace:
#roll = #roll.sort.uniq
if (0..1).any? {|x| (#roll[x+3] - #roll[x+2] == 1) && (#roll[x+2] - #roll[x+1] == 1) && (#roll[x+1] - #roll[x] == 1)}
with this:
if has_straight(roll, 4)
And define has_straight:
def has_straight( roll, need )
num = 1
roll = roll.sort.uniq
roll.each_with_index do |e, i|
if i < roll.length-1 then
if (roll[i+1] - roll[i]) > 1 then
break if num >= need
num = 1
end
num += 1
end
end
num >= need
end
There may be a slightly more clever Ruby-ism that will do this, but it fixes your array out-of-bounds issue.

Resources