Ruby one-liner and warning: 'else without rescue is useless' - ruby

I'm trying to print a basic triangle pattern with a Ruby function which only accepts positive odd number for n
def triangle(n, chars)
puts "#{n} must be odd and positive" if n % 2 == 0 || n < 0 else (n + 1).times { |i| puts chars * i }
end
The problem is this function accepts not only odd but also positive n.
triangle(3, '#')would print
#
##
###
but 'triangle(4, '#')' also works fine
#
##
###
####
It seems my if statement is not working correctly and I get the warning else without rescue is useless. Why and how should I fix this?

Ruby is interpreting your code as two separate statements.
puts "#{n} must be odd and positive" if n % 2 == 0 || n < 0
else (n + 1).times { |i| puts chars * i }
The else is not associated with the if. Ruby is, I guess in desperation, interpreting that as part of a begin/rescue/else condition. Why it's not a syntax error, I have no idea, but it's interpreting it as having no begin block which is technically "successful" so the else always runs.
Conditional statements like do this if that are intended only for simple conditions covering simple statements. Trying to wedge in an else condition is right out. Instead, use a normal condition.
def triangle(n, chars)
if n % 2 == 0 || n < 0
puts "#{n} must be odd and positive"
else
(n + 1).times { |i| puts chars * i }
end
end
In general, avoid the else entirely by taking care of the error condition immediately. It avoids nesting the bulk of the function in an else block. This is more relevant for longer functions, but it's a good habit to get into.
def triangle(n, chars)
if n % 2 == 0 || n < 0
puts "#{n} must be odd and positive"
return nil
end
(n + 1).times { |i| puts chars * i }
end
Finally, errors should be handled with exceptions, not printed error messages. Exceptions can be caught and dealt with by the caller, printed error messages are difficult to catch and bubble up to the user. Exceptions, if not dealt with, halt the program; if the user forgets to handle an error the program will stop and they'll know to fix it. Printed error messages simply let the program plow forward and can be ignored leading to further problems down the road.
Exceptions can also be categorized allowing the caller to figure out what sort of error happened and act appropriately.
def triangle(n, chars)
if n % 2 == 0 || n < 0
raise ArgumentError, "#{n} must be odd and positive"
end
(n + 1).times { |i| puts chars * i }
end

The problem seems to be the flow control is getting confused with the logic as to what is output. This will do what you want, I think:
def triangle(n, chars)
if (n % 2 == 0) || (n < 0)
puts "#{n} must be odd and positive"
else
(n + 1).times { |i| puts chars * i }
end
end

As a more graceful implementation lets take this a step further and handle unexpected arguments
def triangle(n, chars='#')
raise(ArgumentError, "{n} must be odd and positive") unless n.to_i.odd? && n.to_i > 0
1.upto(n.to_i) { |i| chars.to_s * i}
end
This will now handle any n that responds to to_i and any chars that responds to to_s. e.g. '13', ['x', 'x', 1] are still valid arguments even if they make a weird triangle.
Ruby is extremely supportive of duck typing in this fashion and it makes your code less type specific.

Related

ruby weird behavior with integer#times and modulo

If I run this
100.times do |i|
unless i == 0 || i.modulo(2) == 0
p "odd number #{i}"
end
end
I only get back odd numbers, which is the way it should work.
if I run this though
100.times do |i|
unless i == 0 || i.modulo(3) == 0
p "even number #{i}"
end
end
then I get back a mixture of numbers, some of which are even.
Maybe it's me, or 'unless' isn't the best control to use here. Kind of weird though that one gives me the result I want, the other not.
i.modulo(3) == 0 is not a test for odd; it is a is a test of numbers divisible by 3.
Recall the definition of even is divisible by two (or x % 2 == 0) and odd is !even. Therefore only modulo test for even vs odd is mod 2 with a result of 0 or 1.
Example:
100.times { |i|
p "even number #{i}" unless i % 2==1 # better as if i % 2==0
p "odd number #{i}" unless i % 2==0 # better as if i % 2==1
}
To keep it straight, you can also use .even? and .odd?

Understanding 'next' in ruby - comparing solutions

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

When and Why use Loop Do Construct in Ruby

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

Confusion with the order of execution when `next` with `unless` in ruby

The next statement is used to skip a part of the loop and continue with the next iteration of the loop. It can be used in combination with for and while statements.
I have seen people using next if there is complicated piece of code after some condition is being evaluated i.e
next if #state!=:some_state
# some long complicated code
Now here I have played with the next in my IRB as below :
n = 1
loop do
n = n + 1
next unless n == 10
print "Good"
break
end
# Good=> nil
The above one understood. Nicely clear.
n = 1
#=> 1
loop do
print "#{n}"
n = n + 1
next puts "hi" unless n == 5
p "good"
break
end
#1hi
#2hi
#3hi
#4"good"
#=> nil
In the above code, couldn't understand about which order the lines puts "hi" and unless n == 5 executed. Which executed first?
The below one leads to the infinite Loop.
n = 1
#=> 1
loop do
print "#{n}"
n = n + 1
next puts "hi"; 2 + 3 unless n == 5
p "good"
break
end
whereas this one is good:
n = 1
#=> 1
loop do
print "#{n}"
n = n + 1
next puts "hi", 2 + 3 unless n == 5
p "good"
break
end
#1hi
#5
#2hi
#5
#3hi
#5
#4"good"
#=> nil
Please help me here to understand - how does this one resolve that forever loop ?
A semicolon is evaled as a line break so:
next puts "hi"; 2 + 3 unless n == 5
would be equivalent to:
next puts "hi"
2 + 3 unless n == 5
Therefore, next will always be called and you'll have an infinite loop.
The comma is evaled as passing a set of arguments (which is interpreted as an array by puts method signature), so:
next puts "hi", 2 + 3 unless n == 5
is equivalent to:
next puts("hi", 2 + 3) unless n == 5
Regarding the execution order of puts and unless - consider the following:
unless n == 5
next puts "hi"
end
In this example, it is obvious that unless is evaluated first, then if the condition passed is evaluated to false the next puts "hi" statement is executed. Well:
next puts "hi" unless n == 5
is shorthand for exactly the same thing. So the unless modifier will always be evaluated first. Naturally, if you insert a semicolon in the middle, it would cause this to be evaluated differently, since the semicolon is evaluated as a line break.
The conditional has to execute first, otherwise, how would it even know whether to evaluate any expressions involving the statement?
As to your second question, the value of the next expression is ignored for loops, the value in the expression is only useful to return a value from a block. So, the only thing that makes your loop end is the break.

How to execute multiple succeeding functions in 1 line in Ruby?

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.

Resources