How can I compare a nil with an integer? - ruby

With Ruby 2.4, I have this in part of my "if" statement
row_data.index{|x| DataHelper.my_function(x) } > num_var
Unfortunately, the above statement dies with an error if "row_data.index{|x| DataHelper.my_function(x) }" evaluates to nil. Is there any way to rewrite the above so that it would return "false" if "row_data.index{|x| DataHelper.my_function(x) }" evaluated to nil? I don't want to store the expression in a variable prior to my "if" statement because I might not need to even execute that statement if execution doesn't reach there. I feel like there's a one-liner but I don't know what it is.

Short circuit evaluations is the right way checking nil or false conditionals for two important reasons.
Easy way out explicit conversions (to_s, to_i etc) can save you momentarily from raised exceptions/errors but at times can play the devil trick to break your conditionals when one of your compared values of the conditional is from - 0, "", [] and etc. Hence, explicit cares are to be taken considering your code might not last longer enough after a point of time.
Ex. - 1
if x.to_i > -1
puts x "is not a negative integer"
else
puts x "is a negative integer"
end
It can be dangerous as nil.to_i :=> 0 gets approved at if x.to_i > -1 logic check entering into conditional block with converted value (0 in case of nil.to_i).
Probably, you won't mind for ex. - 1 to print a nil as: 0 is not a negative integer. How about this?
if x.to_i
puts " 1/x is" 1/x
end
It can further raise ZeroDivisionError: divided by 0 for each x as nil and you have pay extra care in these cases. May be you did not want to entertain nil inside your block from the first place.
Performance and CLEAN Code are two buzz words you hear everytime. Short circuit evaluations (&&) do not bother about succeeding conditionals if preceding condition is falsewhich makes conditionals execute faster. Additionally, It protects nil values entering into your conditional block and make it more vulnerable.
Answer to your ask:
if (not row_data.index{|x| DataHelper.my_function(x) }.nil?) && (row_data.index{|x| DataHelper.my_function(x) } > num_var)
# do your if block here
# this keeps nil away
else
puts "row_data.index{|x| DataHelper.my_function(x) } is nil"
end

You can take advantage of nil.to_i returning 0
if row_data.index{ |x| DataHelper.my_function(x) }.to_i > num_var
# index is bigger than num_var
else
# index is smaller or equal to num_var
end
Depending on what my_function and num_var represent, you may need to also account for the case of num_var == 0.

Related

Case code in Ruby program not working with a passed value

Have written some test code for a program, trying to pass 2 values, a file and a number. The below doesn't work at all, but if I have something like puts "test" (outside the case) it works.
def read_album(music_file, number)
puts number #(this does something)
case number.to_i
when(number > 1)
puts "done"
when(number < 2)
puts "something"
when(number == 3)
puts "none of this inside case is working"
end
end
def main()
a_file = File.new("albums.txt", "r")
print("Choose album id: ")
choice_of_album = gets().to_i
read_album(a_file, choice_of_album)
end
main()
Your cases are not doing what you think. The expressions given to when are evaluated and the result will be compared to the case value using the case equality operator ===. An expression such as number > 1 will evaluate to either true or false. It makes no sense to compare this result to an integer in Ruby.
You should compare against the constants directly.
case number
when 1
# handle 1
when 2
# handle 2
when 3
# handle 3
else
# handle unknown case; error?
end
Note that other classes may override === to provide useful behavior. The Range and Regexp classes, for example, do this.
case number
when 1..3
# handle 1, 2 and 3
end
case string
when /pattern/
# handle pattern
end
Notably, the Proc class also does this!
def greater_than(n)
proc { |x| x > n }
end
case number
when greater_than(2)
# handle number > 2
end
You need to drop the number.to_i from the case statement.
Or do something like
case number.to_i
when 1..2
puts "foo"
when 3..100
puts "bar"
else
puts "foobar"
end
end
From the Ruby docs
Case statements consist of an optional condition, which is in the position of an argument to case, and zero or more when clauses. The first when clause to match the condition (or to evaluate to Boolean truth, if the condition is null) “wins”, and its code stanza is executed. The value of the case statement is the value of the successful when clause, or nil if there is no such clause.
Your version would evaluate to somehting like
if (number > 1) === number.to_i
and since you are comparing a number with a boolean expression this will not evaluate to true. If you had an else in the case statement this would have been called.

Checking for prime number in ruby

I am trying to write a method that takes a number and checks if its a prime number. After doing some research a fast way to check is to divide the number by every number between 2 and sqrt(number we are checking). I want my method to return true if it is a prime number and false if it isn't.
So I tried to write code that made logical sense to me but I am getting an error. Here's what I have written:
def PrimeTime(num)
counter = 2
while counter <= Math.sqrt(num).ceil
(counter == Math.sqrt(num).ceil) ? "false"
(num % counter == 0) ? "true" : counter += 1
end
end
This gives me
(eval):429: (eval):429: compile error (SyntaxError)
(eval):422: syntax error, unexpected '\n'
Rewritten code
def prime?(num)
(2..Math.sqrt(num).ceil).to_a.each do |number|
if num % number == 0
return false
else
return true
end
end
end
FYI, this is not homework. I am going through coderbyte problems. Any help is appreciated!
The proximate issue you are facing is, this is not valid Ruby: (counter == Math.sqrt(num).ceil) ? "false"
?, as an operator, is a part of the trinary operator ... ? ... : ..., and always comes in pair with a :, as you write in your next line. Then again, overuse of trinary operator is also not good. You also have a problem with control flow: after evaluating "true", the loop will continue, counter won't change, and you got an infinite loop.
I suggest you work out what the algorithm should be. Write it in English, if necessary. Then make sure you convert it to Ruby correctly.
Also, Ruby methods should be in snake case (lowercase with underscores between words), so PrimeTime is not a good name. I suggest prime? (as question marks are also allowed in identifiers) if you will be returning a boolean value (true or false). If you are returning a string (as you seem to be trying to do), try check_for_primality or something similar (without the question mark).
Also... if remainder is zero, the number is not prime. I think you have your tests switched around.
If you are still stumped:
def prime?(num); (2..Math.sqrt(num)).each do |counter|; if (num % counter == 0); return false end end; true; end
EDIT On rewritten code: break & return false doesn't do what you want. They are both control statements; if you break, return won't happen. Even if it did, if the break wasn't there, it would have been better to write and, or at least &&, not & (binary and).
Your logic is still wrong though: PrimeTime(16) is true, for example, is not really what I'd expect from a primality testing function.
In my opinion, your making this way more complicated than it should be. Here's the code that I would advise using.
require 'prime'
puts 2.prime?
Its that simple. And if you want to make your own method
require 'prime'
def prime?(num)
num.prime?
end
Ruby comes with predefined classes such as Prime. All you have to do is to require that class into your project.
require 'prime'
Than, you can use some of the Prime methods such as first to get first x prime elements:
Prime.first(5) # Ret => [2, 3, 5, 6, 11]
Or you could do something like this:
Prime.each(100) do |prime|
p prime # Ret => [2, 3, 5, 7, 11, ..., 97]
end
I hope this may helpful to you.. via miksiii
You can do it without Math.sqrt this way:
def is_prime?(number)
(2..number-1).each {|n| return false if number <= 1 || number % n == 0}
return true
end

How to run a simple Ruby script

I would like to make a program that checks to see if the number you enter is an even number. Sort of like making a leap year program but for any number divisible by 2.
Something along the lines of:
num = gets.chomp
while num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
end
I knows there's something easy that I need to change for it to run.
(btw I just started learning Ruby yesterday!)
There are two problems here.
First being something that others have put, you need to make sure you turn the input into an integer using ".to_i" on your num variable.
Secondly, this code puts you into an infinite loop since you are using a "while" loop.
Since the number is only input once, you get stuck in the "while" loop forever no matter what the input is. Basically, "num" never stops being not 0.
You'd be better off using an if..else statement. Something like:
num = gets.chomp.to_i
if num != 0
if (num%2) == 0
puts 'yess'
else
puts 'nooo'
end
else
puts "that's 0, dude"
end
Integers have two methods for this. They are even? and odd?.
You can use this in your if statement as so:
if num.even?
puts 'yess'
else
puts 'nooo'
end
However, an easier way to write this is with ternary expressions:
puts num.even? ? "yes" : "no"
However, make sure num is an Integer. Anything coming from gets will be a String. So, you should be doing num = gets.chomp.to_i. Anything that is not a number, like "h", will return 0.
"5".to_i #=> 5
"h".to_i #=> 0

what does nil mean/represent here?

Following are the simple statements in the irb shell. What does nilin the output mean ? Why does it accompany the print statement in the if block ?
irb(main):062:0> if(x==20 && y==30)
irb(main):063:1> print("if statement working !")
irb(main):064:1> else
irb(main):065:1* print("else statement working !!")
irb(main):066:1> end
if statement working !=> nil # what does nil represent here ?
In Ruby, all expressions return values, even if it's nil. Blocks and methods simply return the value of the last expression evaluated. There are many ways to use this effectively. For example, this is the reason explicit returns are often not used. Also, you can do this:
print if x == 20 && y == 30
'if statement working!'
else
'else statement working!'
end
Regarding your example: in addition to printing the string as you instructed, irb will display the value it received from the if-else blocks. Since print always returns nil, both branches will return the same value.
It means that your if-block does not return a value (which it can, actually). For instance, the following is perfectly legal and viable:
foo = if bar > 10
42
else
0
end
# now, foo is either 42 or 0

Odd Ruby If Statement Question

I've noticed this little oddity(I think) in If Statements in Ruby. Here's an example:
my_number = nil
if my_number < 3
'number is less than 3'
end
Obviously, when you run this code you'll get a "comparison of Fixnum with nil failed" error. Now here's something strange. If I make a little change in the If Statement to check for nil, it works fine. Example:
my_number = nil
if my_number && my_number < 3
'number is less than 3'
end
Adding the check for nil makes it not crash. This may all sound stupid but I can't figure out why that works. Shouldn't it still throw an error?
Thanks to anyone who can explain this. :) Thanks!
Boolean expressions are evaluated in what is known as "short circuit" fashion. That is, as soon as it know the result, it doesn't keep trying to evaluate expressions.
So it does the if my_number and since that's false, there is no need to continue, because false && <anything> is always false.
This is a useful language feature, and many languages work like this (the original Visual Basic is one exception that I can think of) because it lets you do exactly this sort of test without requiring cumbersome nested 'if's.
This is no way specific to Ruby: I've noticed this behaviour in all languages I've ever used, from Pascal to Java.
If you have boolean expression b1 && b2 && b3 ... && bn, most languages guarantee that bi will be evaluated from left to right and if some bi turns out to be false, evaluation will be stopped. (because whole expression is false then). Same for boolean || operator.
It has to be OK to test for nil, so if nil or something like it is OK in almost every language.
But for an arithmetic comparison, if it didn't throw an exception it would have to return true or false. Either way is problematic.
True kind of doesn't make sense, as nil would be both < and > than 3.
False is almost as bad, as now nil < 3 and nil >= 3 are both false, and that's not ideal.
So, the comparison method throws an exception. Problem solved.
nil is "falsy". Try this in irb:
irb(main):001:0> puts "Nil is true " if nil
=> nil
irb(main):002:0> puts "Nil is not true " if !nil
Nil is not true
=> nil
nil isn't the same as false, but making it act as such help a lot in loops and other tests:
false == nil
=> false
Since the first part of your and is false ruby does the lazy thing and doesn't even bother to evaluate the next bit, if it's > 3.
What's happening is called short-circuit evaluation. You're statement can be thought of like this:
if( my_number )
if( my_number < 3)
'number is less than 3'
end
end
Since the first condition is false there's no reason to evaluate the second condition of the statement -- the my_number < 3 part.

Resources