So I am writing a Ruby program for school that changes the value of a boolean to true if a certain value is either 1 or 3, and to false if it is 0 or 2. Since I come from a Java background, I thought that this code should work: if n == 1 || n == 3
But it does not. So my question here is is it possible to use an "Or" expression thingy in If blocks in Ruby? I know that my current situation could be solved easily by just something like the following:
if n == 0
t_o_f = false
elsif n == 1
t_o_f = true
Et Cetera. But I want to know if I can use an Or in If blocks for the future.
Yes, any expression can be used in an if condition, including those using the || (logical or) operator.
As with Java, Ruby's || operator short-circuits. That is, if the left side is true, the right side is not evaluated.
Idiomatic ruby uses postfix if for one-liners:
puts "Yes" if n == 4 || n == 5
Avoid postfix if the line is long, however, and break it into multiple lines:
if n == 4 || n == 5
puts "This is a big long string to be output....................."
end
That's because postfix if can get visually lost at the end of a long line.
You can have a one-liner with prefix if, but it's not commonly seen:
if n == 4 || n == 5 then puts "foo" end
or, perhaps:
if n == 4 || n == 5 ; puts "foo" ; end
This is really a multi-line if condensed into one line; the semicolons act as line breaks.
When testing for multiple conditions, it can sometimes be valuable to use Array#include?:
puts "foo" if [4, 5].include?(n)
The value of this for only two conditions is not that great. For three or more, it reads well.
The or operator works, and you can write the keyword too:
if n==1 or n==2
end
http://www.tutorialspoint.com/ruby/ruby_operators.htm
And you could also write what you want this way:
x = (n%2) ? true : false
In addition to #Wayne Conrad: if there is little or no 'logic' deciding if n is true or false, then this is also a good option:
result = case n
when 1, 3 then true
when 0, 2 then false
end
Related
This question already has answers here:
Shortcut to make case/switch return a value
(4 answers)
Closed 6 years ago.
I have this code
(1..50).each do |num|
case num
when num % 4 == 0, num % 6 == 0
puts 'Cluck'
when num % 4 == 0
puts 'Cluck Cluck'
when num % 5 == 0
puts 'Cluck Cluck Cluck'
else
puts num
end
end
For some odd reason, instead of putting cluck cluck on the fourth line or cluck on the 24th line, it's just putting a list of 1 through 100. I can't figure out what's wrong with the switch statement. The first when using the comma or && doesn't change anything either (which I don't believe it should).
Problems
case a when b
case a
when b
tests if a is equal to b.
In your case, a is a number (num) and b is a boolean (num % 4 == 0) so this never happens.
when b,c
Another problem is that
case
when b,c
tests if b or c.
If you want to check that num is divisible by 24, you need b and c.
Solution
Remove num from case and use logical and (&&) :
(1..100).each do |num|
case
when num % 4 == 0 && num % 6 == 0
## or just :
# when num % 24 == 0
puts 'Cluck'
when num % 4 == 0
puts 'Cluck Cluck'
when num % 5 == 0
puts 'Cluck Cluck Cluck'
else
puts num
end
end
Oh well, Eric's answer is right on the money. I'd just add this as a reference -
It doesn’t end there though you can use a case statement without giving it a value to match against, which allows a case statement to mimic the behavior of an if statement, e.g.:
print "Enter a string: "
some_string = gets.chomp
case
when some_string.match(/\d/)
puts 'String has numbers'
when some_string.match(/[a-zA-Z]/)
puts 'String has letters'
else
puts 'String has no numbers or letters'
end
I read over this guide quick, and it seems to be that you're trying to use the case as an if statement, but you supplied a value to match against.
Because you gave num as the first argument of case, it's expecting to match against it. The problem is, your conditions evaluate to boolean values, and num is a number, so they'll never match, and the else condition will always be run.
Remove the num from the start of the case.
I'm doing an online course:
Write a method that takes a string and returns true if the letter "z" appears within three letters after an "a". You may assume that the string contains only lowercase letters.
This is the solution given:
def nearby_az(string)
i = 0
while i < string.length
if string[i] != "a"
i += 1
next
end
j = i + 1
while (j < string.length) && (j <= i + 3)
if string[j] == "z"
return true
end
j += 1
end
i += 1
end
return false
end
This solution seems unnecessarily complex to me. Specifically, I don't understand why next is needed. I was wondering if someone could help me understand this function.
My solution appears to work as well with the tests I tried, but I'm wondering if the other solution is better and if my solution would have problems that I just haven't come across yet.
def nearby_az(string)
i = 0
while i < string.length
while string[i] != "a"
i += 1
end
if string[i + 1] == "z" || string[i + 2] == "z" || string[i + 3] == "z"
return true
else
i += 1
end
return false
end
end
In the original answer, if you remove next, the i index will be assumed to be representing an "a" position even if it is not, and will return a wrong result.
When you pass a string like "b" to your code, it will go into an endless loop because the outer condition while i < string.length has no control over:
while string[i] != "a"
i += 1
end
Notice that, once i is beyond the last position of a string, the condition string[i] becomes nil, and string[i] != "a" will be satisfied from there on.
Your solution will not work if the string will look like this "bbbbb..." or like this "abb" - that is -
1) your code will crash if string.length < 4 (no string[i+3])
2) your code will crash if no "a"s are in the string.
And here the "next" came in handy:
The purpose of the "next" is to skip the rest of the loop and jump right back to the start of it. So the original solution will first go over chars until it finds on "a" (skipping the other part of the loop is not) and when and only when it finds "a" - it goes to find the "z".
So, as sawa stated, your loop doesn't accept strings without an a in them. It also doesn't understand strings with multiple a's. For example aaaaaaaz will return false because it finds the first a, checks the next 3 doesn't find a z and bails out.
You can solve your problem by removing the return false from the end and adding the same length condition as the outer loop to the inner loop.
His use of next is equivalent to the above. It is a way of threading the two things together. It is needlessly complex though, I agree.
A far simpler way (assuming you don't want to use regexps) is to just track the last occurance of an 'a'.
def nearby_az(string)
last_a = -4
string.chars.each_with_index do |c, i|
last_a = i if c == 'a'
return true if c == 'z' and i - last_a <= 3
end
return false
end
I have this code to return true if num is a power of 2.
def is_power_of_two?(num)
result = num.inject(0) {|n1, n2| n2 ** n1}
if result == num
true
else
false
end
end
p is_power_of_two?(16)
I keep getting an error though. How could I fix and simplify this code?
Clearly, n is a non-negative integer.
Code
def po2?(n)
n.to_s(2).count('1') == 1
end
Examples
po2? 0 #=> false
po2? 1 #=> true
po2? 32 #=> true
po2? 33 #=> false
Explanation
Fixnum#to_s provides the string representation of an integer (the receiver) for a given base. The method's argument, which defaults to 10, is the base. For example:
16.to_s #=> "16"
16.to_s(8) #=> "20"
16.to_s(16) #=> "10"
15.to_s(16) #=> "f"
It's base 2 we're interested in. For powers of 2:
1.to_s(2) #=> "1"
2.to_s(2) #=> "10"
4.to_s(2) #=> "100"
8.to_s(2) #=> "1000"
16.to_s(2) #=> "10000"
For a few natural numbers that are are not powers of 2:
3.to_s(2) #=> "11"
5.to_s(2) #=> "101"
11.to_s(2) #=> "1011"
We therefore wish to match binary strings that contain one 1.
Another Way
R = /
\A # match beginning of string ("anchor")
10* # match 1 followed by zero or more zeroes
\z # match end of string ("anchor")
/x # free-spacing regex definition mode
def po2?(n)
(n.to_s(2) =~ R) ? true : false
end
po2?(4) #=> true
po2?(5) #=> false
And one for the road
This uses Fixnum#bit_length and Fixnum#[]:
def po2?(n)
m = n.bit_length-1
n[m] == 1 and m.times.all? { |i| n[i].zero? }
end
po2? 0 #=> false
po2? 1 #=> true
po2? 32 #=> true
po2? 33 #=> false
Try:
def is_power_of_two?(num)
num != 0 && (num & (num - 1)) == 0
end
It is well explained here (for C#, but #GregHewgill's explanation applies here as well)
I would do something like this, using Ruby's Math module.
def power_of_two?(n)
Math.log2(n) % 1 == 0
end
Or, if you wanted to be really cool:
def power_of_two?(n)
(Math.log2(n) % 1).zero?
end
Some IRB output:
2.1.0 :004 > power_of_two?(2)
=> true
2.1.0 :005 > power_of_two?(32768)
=> true
2.1.0 :006 > power_of_two?(65536)
=> true
This method assumes that the input is a positive integer.
Source
Another way to solve this is to go the other way around than most of the answers here - we can use the number 1 to start and find out if the number is the power of two. Like this:
def power_of_two?(num)
product = 1
while product < num
product *= 2
end
product == num
end
We start with 1. Then we multiply the 1 by 2, and keep multiplying by 2 until the product is larger than num (product < num). Once we hit that condition, we stop, exit the loop, and check if it's equal to num (product == num). If it is, the num is the power of 2.
As was pointed out in the comments above, you were getting errors because you're trying to use the inject method on a non-iterable (an int). Here's a solution using the suggested log2
def is_power_of_two?(num)
result = Math.log2(num)
result == Integer(result)
end
Note: will fail with very big numbers close to binaries (like 2 ^ 64 - 1). A foolproof version (but slower) would be:
def is_power_of_two?(num)
while (num % 2 == 0 and num != 0)
num /= 2
end
num == 1
end
Please comment any improvements that any of you may find.
Here is another solution that uses recursion:
def power_of_2?(number)
return true if number == 1
return false if number == 0 || number % 2 != 0
power_of_2?(number / 2)
end
In my opinion, the easiest -- but maybe a little long -- way of doing what you need to do is just writing this recursive method like so:
def power_of_two?(number)
continue = true
if number == 1
return true
end
if number % 2 != 0
return false
else
while continue == true do
if number.to_f / 2.0 == 2.0
continue = false
return true
else
if number % 2 != 0
continue = false
return false
else
number /= 2
continue = true
end
end
end
end
end
One is a power of two (2^0), so it first checks if the number given is 1. If not, it checks if it is odd, because 1 is the only odd number that is a power of two.
If it is odd it returns false and moves on to the else statement. It will check if the number divided by 2 is two, because then it would obviously be a power of 2. It does this as a float, because 5/2 in Ruby would return 2.
If that is false, it then again checks if the number is odd -- unnecessary on the first round, necessary after that. If the number is not odd, it will divide the number by two and then do the loop another time.
This will continue until the program resolves itself by getting 2 or any odd number, and returns true or false, respectively.
I ran into this one in a bootcamp application prep. I'm not a math person and don't understand a few of these methods, so I wanted to submit a common sense approach for people like me. this requires little knowledge of math, except to know a number to the second power will be the result of some number multiplied by itself.
def is_power_of_two?(num)
num.times {|n| return true if (n+1) * (n+1) == num}
false
end
this method counts up to the num variable starting at 1 and returns true if (any of those numbers in the sequence multiplied by itself) is equal to num & if num is not 0 (more on that below).
example:
num = 9
1 * 1 == 9 #=> false
2 * 2 == 9 #=> false
3 * 3 == 9 #=> true
true is returned and method is finished running.
the #times method requires an integer > 0, so this edge case is "handled" by virtue of the fact that #times does nothing with "0" as the variable and returns false when outside of the #times iteration.
def power_of_two?(num)
num.to_s(2).scan(/1/).length == 1
end
I recently came up across a problem/solution that used Loop Do. I seldom have seen this so far in my learning Ruby Programming (I am a beginner with no CS experience).
# 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 (see example beow), choose the earliest (left-most)
# of the two indices. If no number in `arr` is largr than `arr[i]`,
# return `nil`.
#
# Difficulty: 2/5
describe "#nearest_larger" do
it "handles a simple case to the right" do
nearest_larger([2,3,4,8], 2).should == 3
end
it "handles a simple case to the left" do
nearest_larger([2,8,4,3], 2).should == 1
end
it "treats any two larger numbers like a tie" do
nearest_larger([2,6,4,8], 2).should == 1
end
it "should choose the left case in a tie" do
nearest_larger([2,6,4,6], 2).should == 1
end
it "handles a case with an answer > 1 distance to the left" do
nearest_larger([8,2,4,3], 2).should == 0
end
it "handles a case with an answer > 1 distance to the right" do
nearest_larger([2,4,3,8], 1).should == 3
end
it "should return nil if no larger number is found" do
nearest_larger( [2, 6, 4, 8], 3).should == nil
end
end
SOLUTION
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
nearest_larger([2,4,3,8], 1)
Can someone please explain to me when is the best time to use a "loop do" construct instead of the usual "while" or "unless" or "each" construct?
Adding up to the previous answers,
The "loop do" construct also offers a cleaner syntax when working with external iterators, e.g
No "loop do"
my_iterator = (1..9).each
begin
while(true)
puts my_iterator.next
end
rescue StopIteration => e
puts e
end
And now with "loop do" this would become
my_iterator = (1..9).each
loop do
puts my_iterator.next
end
And the exception is handled for you. It also allows you to loop through two collections at the same time and as soon as one of them runs out of elements the loop exits gracefully,
iterator = (1..9).each
iterator_two = (1..5).each
loop do
puts iterator.next
puts iterator_two.next
end
It will print: 1,1,2,2,3,3,4,4,5,5,6.
More info on it at: ruby-docs.org
In a language without loop, you might use a while construct like:
while( true ) {
# Do stuff until you detect it is done
if (done) break;
}
The point of it is that you start the loop without knowing how many of iterations to perform (or it is hard to calculate in advance), but it is easy to detect when the loop should end. In addition, for a particular case you might find the equivalent while (! done) { # do stuff } syntax clumsy, because the done condition can happen halfway through the loop, or in multiple places.
Ruby's loop is basically the same thing as the while( true ) - in fact you can use while( true ) almost interchangeably with it.
In the given example, there are following points of return within each iteration:
if (left >= 0) && (arr[left] > arr[idx])
return left # <-- HERE
elsif (right < arr.length) && (arr[right] > arr[idx])
return right # <-- HERE
elsif (left < 0) && (right >= arr.length)
return nil # <-- HERE
end
There is also an implied "else continue looping" here, if no end conditions are met.
These multiple possible exit points are presumably why the author chose the loop construct, although there are many ways of solving this problem in practice with Ruby. The given solution code is not necessarily superior to all other possibilities.
Using the loop do construct allows you to break on a conditional.
for instance:
i=0
loop do
i+=1
print "#{i} "
break if i==10
end
You would want to use this when you know the number of elements that will be processed, similar to that of the for each loop
loop with 'loop' construct will execute the given block endlessly
until the code inside the block breaks on certain condition.
it can be used when you don't have a collection to loop over, the
places where 'each' and 'for' cannot work.
the different between 'loop' and while/until is that while/until will
execute the given block when certain condition is meet, where as in
case of loop there is no condition to start, condition lies inside the
loop's block.
for better understanding read doc.
http://www.ruby-doc.org/core-1.9.2/Kernel.html#method-i-loop
Suppose You wanted to put a number of conditions, it might be neater to put them together. Instead of this, for example:
x = 0
while x <= 10
num = gets.to_f
break if num < 1
break if /\D/.match? num.to_s
puts num ** 2
end
Grouping the breaks together makes it more readable
x = 0
loop do
num = gets.to_f
break if num < 1
break if x <= 10
break if /\D/.match? num.to_s
puts num ** 2
end
I have two succeeding function with the same condition and I wonder what is the best way to write this? I know the one way to do this is using if (condition) ... end, but I'm wondering if I can do it in one-line similar to bash, '[$n == $value] echo "$n" && break'.
n = 0
loop do
puts n if n == value # puts and break is having the same condition, but
break if n == value # can we do it in one line?
n += 1
end
Because n is truthy, you can use the 'and' joiner. It reads really nicely:
n = 0
loop do
puts n and break if n == value
n += 1
end
--edit--
As pointed out in comments, that won't actually work because puts returns nil, which isn't truthy. My bad. You can use 'or' instead, but that doesn't read nicely. So I'd say just group the statements with parenthesis.
n = 0
loop do
(puts n; break) if n == value
n += 1
end
You could also change the puts method to return the value it prints, and that would work with 'and', but that's probably not the smartest idea :)
I'm guessing your actual code is different to what you've pasted, so if the first method in your chain returns something, you can use 'and'.
One easy way is to just parenthesize the statements:
ruby-1.9.1-p378 > 0.upto(5) do |n|
ruby-1.9.1-p378 > (puts n; break;) if n == 3
ruby-1.9.1-p378 ?> puts ">>#{n}<<"
ruby-1.9.1-p378 ?> end
>>0<<
>>1<<
>>2<<
3
If it's a bit much to put in parentheses, a begin-end will do the trick:
0.upto(5) do |n|
begin
puts "I found a matching n!"
puts n
puts "And if you multiply it by 10, it is #{10*n}"
break;
end if n == 3
puts "((#{n}))"
end
Output:
((0))
((1))
((2))
I found a matching n!
3
And if you multiply it by 10, it is 30
proc { puts n; break; }.() if n == 3
One of the golden rules of Ruby is that if you are writing a loop, you are probably doing it wrong. In this particular case, all that your loop is doing is to find an element in a collection. In Ruby, there already is a method for finding an element in a collection: Enumerable#find. There is no need to write your own.
So, the code gets simplified to:
puts (0...1.0/0).find {|n| n == value }
Now that we have a nice declarative formulation of the problem, it is easy to see that (assuming sane equality semantics and sane semantics of value.to_s), this is exactly the same as:
puts value
So, the whole loop was completely unnecessary to begin with.