How to Break from Nested Loops in Ruby

How to break from a nested loop to a parent loop that is more than one level above which requires a value provided by the nested loop

You can use multiple break statements.

For example:

xxx.delete_if do |x|
result = yyy.each do |y|
result2 = zzz.each do |z|
if x + y == z
break true
end
end
break true if result2 == true
end
result == true
end

However I would definitely avoid this in your particular situation.

You shouldn't be assigning variables to the result of each. Use map, reduce, select, reject, any?, all?, etc. instead

It makes more sense to use any? to accomplish the same purpose:

xxx.delete_if do |x|
yyy.any? do |y|
zzz.any? do |z|
x + y == z
end
end
end

How to break outer cycle in Ruby?

What you want is non-local control-flow, which Ruby has several options for doing:

  • Continuations,
  • Exceptions, and
  • throw/catch

Continuations

Pros:

  • Continuations are the standard mechanism for non-local control-flow. In fact, you can build any non-local control-flow (subroutines, procedures, functions, methods, coroutines, state machines, generators, conditions, exceptions) on top of them: they are pretty much the nicer twin of GOTO.

Cons:

  • Continuations are not a mandatory part of the Ruby Language Specification, which means that some implementations (XRuby, JRuby, Ruby.NET, IronRuby) don't implement them. So, you can't rely on them.

Exceptions

Pros:

  • There is a paper that proves mathematically that Exceptions can be more powerful than Continuations. IOW: they can do everything that continuations can do, and more, so you can use them as a replacement for continuations.
  • Exceptions are universally available.

Cons:

  • They are called "exceptions" which makes people think that they are "only for exceptional circumstances". This means three things: somebody reading your code might not understand it, the implementation might not be optimized for it (and, yes, exceptions are godawful slow in almost any Ruby implementation) and worst of all, you will get sick of all those people constantly, mindlessly babbling "exceptions are only for exceptional circumstances", as soon as they glance at your code. (Of course, they won't even try to understand what you are doing.)

throw/catch

This is (roughly) what it would look like:

catch :aaa do
stuff.each do |otherstuff|
foo.each do |bar|
throw :aaa if somethingbad
end
end
end

Pros:

  • The same as exceptions.
  • In Ruby 1.9, using exceptions for control-flow is actually part of the language specification! Loops, enumerators, iterators and such all use a StopIteration exception for termination.

Cons:

  • The Ruby community hates them even more than using exceptions for control-flow.

How to break inner loop and next for outer loop in ruby?

I got something in the similar matter:

count = 0 
10.times do |i|
(i..20).collect{ |ii| ii < rand(30) || break } || next
count += 1
end

So it is just boolean algebra. if condition is taken place, when all, i.e. result of collect method, isn't nil, so we need to next keyword worked, when result of collect is nil. Therefore we just set or operator between collect and next, in order to next is occuring when result of collect is nil.

Nested loops in Ruby

You are returning the result while you are still in the loop. You need to move result = 0 out of the loop, and move the return result statement outside of the loop too. At the moment the function is going through the first iteration of the loop ("ababaa", for which all characters match), but you want result to equal the sum of all results.

Additionally, instead of doing:

count = 0
x.chars.each do |x|
if x == string[count]
count = count + 1
result = result + 1
else
count = count + 1
end
end

You could use the function each_with_index, to get

x.chars.each_with_index do |c,index|
if c == string[index]
result = result + 1
end
end

However, since you are trying to count how many characters in the substring are a prefix of string, you want to break when you first find a character c that is not equal to string[index], so that you don't end up counting extra characters. The loop then becomes:

x.chars.each_with_index do |c,index|
if c == string[index]
result = result + 1
else
break
end
end

ruby break double statement

You can't break from inside an if, you can only break from inside loops and blocks.

If what you're asking is how to break from two nested loops, you can use catch in combination with throw—these are not the same as try and catch in other languages.

catch(:stop) do
while some_cond
while other_cond
throw :stop
end
end
end

Of course, you can always just set a flag or some such to tell the outer loop that it should break too.

Nested Loops Ruby

Your main problem appears to be in the deciding of which pebbles to paint. The following is not right:

element % round == 0

It should be:

(index+1) % round

You want to compare the pebble's index rather than the current value of the pebble. As well, you need to remember that indexes are 0-based (ie they start counting from 0). You need to have the indexes be 1-based (hence the adding of 1) otherwise the first element would always change and the others would be off by 1.

There was also a typo for pebble_color, which should be pebble_colors.

You could definitely re-factor the code to make it shorter, but the following appears to work (just making the minimal changes mentioned above):

pebbles = (1..10).map {|element| element.to_s}
pebble_colors = (1..10).map {|element| element.to_s}

(1..10).each do |round|
pebbles_to_paint = []
pebbles.each_with_index {|element, index| pebbles_to_paint << index if (index+1) % round == 0}
pebbles_to_paint.each do |pebble_number|
if pebble_colors[pebble_number].include?("w")
pebble_colors[pebble_number].delete!("w")
else
pebble_colors[pebble_number] << "w"
end
end
p pebble_colors
end

The output is:

["1w", "2w", "3w", "4w", "5w", "6w", "7w", "8w", "9w", "10w"]
["1w", "2", "3w", "4", "5w", "6", "7w", "8", "9w", "10"]
["1w", "2", "3", "4", "5w", "6w", "7w", "8", "9", "10"]
["1w", "2", "3", "4w", "5w", "6w", "7w", "8w", "9", "10"]
["1w", "2", "3", "4w", "5", "6w", "7w", "8w", "9", "10w"]
["1w", "2", "3", "4w", "5", "6", "7w", "8w", "9", "10w"]
["1w", "2", "3", "4w", "5", "6", "7", "8w", "9", "10w"]
["1w", "2", "3", "4w", "5", "6", "7", "8", "9", "10w"]
["1w", "2", "3", "4w", "5", "6", "7", "8", "9w", "10w"]
["1w", "2", "3", "4w", "5", "6", "7", "8", "9w", "10"]

I cant break a loop

Your @response is an instance variable so it's encapsulated inside your class Hello and not available outside of it. One of the possible (but not the only one) solutions to make your code work could be as follows

class Hello

# Make @response available in the interface
attr_reader :response

def initialize(a, b)
@a = a
@b = b
end

def something()
@response = "201"

end
end

loop do
puts "write something"
a = gets.chomp
puts "write something again"
b = gets.chomp

hello = Hello.new(a,b)
hello.something()

# using class property to stop the loop
break if hello.response == "201"
end


Related Topics



Leave a reply



Submit