Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 669
JaTo Avatar asked May 29 '13 11:05

JaTo


People also ask

What is looping in Ruby?

Looping in programming languages is a feature which clears the way for the execution of a set of instructions or functions repeatedly when some of the condition evaluates to true or false. Ruby provides the different types of loop to handle the condition based situation in the program to make the programmers task simpler. The loops in Ruby are :

How to execute even condition is false in Ruby while loop?

With the help of doing keyword in Ruby while loop it will execute altealt once even the conditions get failed for the first time, which means even condition is false once the code block will execute on the starting of the execution. Below is the example are mentioned:

What is the use of DO-WHILE loop in Ruby?

The main important facts of the ruby do-while loop are it will execute the loop at least once for the first time and then it will go for checking of the conditions. While Loops in ruby are based on the boolean value which means it works on the true and false value of the conditions.

What is an entry controlled loop in Ruby?

It is also known as Entry Controlled Loop because the condition to be tested is present at the beginning of the loop body. for variable_name [, variable...] in expression [do] # code to be executed end for: A special Ruby keyword which indicates the beginning of the loop.


3 Answers

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

like image 118
radyz Avatar answered Oct 19 '22 18:10

radyz


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.

like image 39
Neil Slater Avatar answered Oct 19 '22 17:10

Neil Slater


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

like image 34
Woot4Moo Avatar answered Oct 19 '22 19:10

Woot4Moo