I have this bit of code:
gates.each do |key, value, temp|
unless value.class == Output
temp = value.in1
gates.each do |k, v|
if v.out == temp
value.base_distance += 1
#do a thing
end
end
end
end
What I want to happen is when the #do a thing comment inside the conditional is reached it should break out of the inner .each loop and move on to the next instance of the outer .each loop, essentially executing a next. How would I do that from inside the conditional?
TL;DR use break.
Here is the MCVE:
[1,2].each do |o|
puts "Outer: #{o}"
[1,2,3].each do |i|
break if i.even?
puts "Inner: #{i}"
end
end
#⇒ Outer: 1
# Inner: 1
# Outer: 2
# Inner: 1
FWIW, one might pass an argument to break to be returned from the block. This might be needed to emulate the next after break:
[1,2].each do |o|
puts "Outer: #{o}"
inner =
[1,2,3].each do |i|
break :next if i.even?
puts "Inner: #{i}"
end
next if inner == :next
...
end
Related
To set i and its maximum and have a double iterator In Java, I would use for loops as follows:
for (i=1; i<10, i+=){
for (j=1; j<10; j++){
puts i (or whatever function)
}
}
I'm trying to figure out how to do this in Ruby. The for loops I've seen in Ruby are for ranges, and single iterator:
for i in (1..10)
puts i
end
or while loops
i = 1
while i < 10
puts i
i += 1
end
Are these while loops the (single iterator) Ruby equivalent of the Java I mentioned, or is there another way to do these for loops?
The "ruby-ish" way would be each
(1...10).each do |i|
puts i
end
or to double iterate
(1...10).each do
(1...10).each do |j|
puts j
end
end
As #maxwilliams and #sawa point out, (1...10) is 1 through 9 inclusive, (1..10) is 1 through 10 inclusive.
Why not do a nested loop?
for i in 1...10
for j in 1...10
puts i
end
end
By the way, the Ruby equivalent is for i in 1...10, not for i in 1..10.
In Ruby you rarely use the for loop. Actually, you never use it. In Ruby you use enumerators and blocks.
for (i=1; i<10, i+=){
for (j=1; j<10; j++){
puts i (or whatever function)
}
}
is equivalent to
(1...10).each do |i|
(1...10).each do |j|
puts j
end
end
Also note there is a difference between
(1..10).each do |i|
end
and
(1...10).each do |i|
end
The latter is equivalent to
(1..9).each do |i|
end
In fact, the .. will create an inclusive range whereas ... an exclusive range.
It is also worth to mention that in Ruby you rarely use indexes to loop items. Therefore, if your goal is to print out some elements in an array, your code should not be
(1..10).each do |i|
p #items[i]
end
rather you call each on the collection.
#items.each do |item|
p item
end
In certain cases, like in your question, you don't even need a range (when your loop starts from 1. You can use times.
9.times do |i|
9.times do |j|
puts j
end
end
In Ruby we don't use parenthesis. They are uncool.
This is an example for while statement in Ruby
while $i < $num do
puts "Value for i is #{i}"
$i +=1
end
And this is an example for for loop.
for i in 0..10
puts "Value of local variable is #{i}"
end
But there are more loops! Check this for more info http://www.tutorialspoint.com/ruby/ruby_loops.htm
But if you are Java programmer, you can check this link https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/to-ruby-from-java/
In Kernel#loop documentation, there is an example that uses break in order to break out of the loop. Otherwise, the documentation talks about rasing a StopIteration error.
I tried them both:
i=0
loop do
puts i
i+=1
break if i==10
end
i=0
loop do
puts i
i+=1
raise StopIteration if i==10
end
The output is the same. Are there differences between the two approaches? I think that there should be, otherwise why bother to define an error class and all the managements that come with it?
break is a keyword in ruby, which terminates the most internal loop, whether it be loop, or for, and a few more (see here).
StopIteration is an exception, which is caught by Kernel.loop (see here).
So in your scenario, they are the same, but in a different scenario, they will act differsntly:
puts "first run"
for i in 0..20 do
puts i
break if i==10
end
puts "first done"
puts "second run"
for i in 0..20 do
puts i
raise StopIteration if i==10
end
puts "second done" # <= will not be printed
Here is a scenario where StopIteration can be utilized when break cannot:
puts "first run"
def first_run(i) # will not compile
puts i
break if i==10
end
i=0
loop do
first_run(i)
i+=1
end
puts "first done"
puts "second run"
def second_run(i)
puts i
raise StopIteration if i==10
end
i=0
loop do
second_run(i)
i+=1
end
puts "second done"
Here is another use-case, which uses the fact the Enumerator.next throws a StopIteration error when the Enumerator has reached the end:
enum = 5.times.to_enum
loop do
p enum.next
end
will print
0
1
2
3
4
Thanks Cary for this example.
There are two uses of the break keyword.
First: the break keyword, when in a block, causes the method that the block was passed to to return. If you pass an argument to break, the return value of the method will be that argument. Here is an example:
def a
puts 'entering method a'
yield
puts 'leaving method a'
end
result = a { break 50 }
puts result
This will print:
entering method a
50
Second: the break keyword can cause a while, until, or for loop to terminate. Here is an example:
i = 0
result =
while i < 5
i += 1
puts i
break 75 if i == 3
end
puts result
This will print:
1
2
3
75
Your example with Kernel#loop makes use of the first case, causing the loop method to return.
StopIteration is an exception which only works with Kernel#loop as far as I can tell. For example:
infinite_loop = Enumerator.new do |y|
i = 0
while true
y << i
i += 1
end
end
infinite_loop.each do |x|
puts x
raise StopIteration if x == 4
end
Fails because StopIteration is uncaught, however:
x = 0
loop.each do
puts x
x += 1
raise StopIteration if x == 4
end
Catches StopIteration and exits.
This is really driving me up a wall.
I have an instance method I'm trying to debug, but I'm running into an issue where my puts and gets aren't showing up inside the instance method.
Code:
#! /usr/bin/env ruby
class Calculator
def evaluate(string)
ops = string.split(' ')
ops.map! do |item|
if item.is_a? Numeric
return item.to_i
else
return item.to_sym
end
end
puts "Got #{string}" #Doesn't output
puts "Converted to #{ops}" #This too
opscopy = ops.clone
ops.each.with_index do |item, index|
if item == :* || item == :/
opscopy[index] = ops[index-1].send(item, ops[index+1])
opscopy[index-1] = opscopy[index+1] = nil
end
end
ops = opscopy.compact
puts "After multi/div #{ops}"
ops.each.with_index do |item, index|
if item == :+ || item == :-
opscopy[index] = ops[index-1].send(item, ops[index+1])
opscopy[index-1] = opscopy[index+1] = nil
end
end
puts "After +/- #{opscopy.compact}"
opscopy.compact.first
end
end
item = Calculator.new.evaluate "4 * 2"
puts "#{item} == 8" #Prints :(
Output:
action#X:~/workspace/ruby$ ./calculator.rb
4 == 8
That return in your map! block is where the problem is.
ops.map! do |item|
if item.is_a? Numeric
return item.to_i # returns from method
else
return item.to_sym # returns from method
end
end
You are returning the method in your map! block before the puts is called.
Change the map! block to:
ops.map! do |item|
item.send(item.is_a?(Numeric) ? :to_i : :to_sym)
end
loop { break } can work fine, but
block = Proc.new { break }
# or
# block = lambda { break }
loop(&block) # => LocalJumpError: break from proc-closure
Is it possible to break in a block variable ?
Update:
A example to explain more:
def odd_loop
i = 1
loop do
yield i
i += 2
end
end
def even_loop
i = 2
loop do
yield i
i += 2
end
end
# This work
odd_loop do |i|
puts i
break if i > 10
end
# This doesn't work
break_greater_10 = Proc.new do |i|
puts i
break if i > 10
end
odd_loop(&break_greater_10) # break from proc-closure (LocalJumpError)
even_loop(&break_greater_10) # break from proc-closure (LocalJumpError)
As my comprehension, Proc.new should work same as block (it can return a function from block), but I don't understand why can't break a loop.
P.S. Sorry for my bad english >~<
To solve this problem you could
raise StopIteration
this worked for me.
To return from a block you can use the next keyword.
def foo
f = Proc.new {next ; p 1}
f.call
return 'hello'
end
puts foo # => 'hello' , without 1
I want to run this code like this
count = Hash.new(0)
while line = gets
words = line.split
words.each do |word|
count[word] += 1
end
end
count.sort{|a, b|
a[1] <=> b[1]
}.each do |key, value|
print "#{key}: #{value}\n"
end
but I don't know how to break. And Hitting Command+C returns
word_count.rb:3:in `gets': Interrupt
from word_count.rb:3:in `gets'
from word_count.rb:3:in `<main>'
How can I fix this code?
You can also trap the signal Ctrl+C sent to the process:
count = Hash.new(0)
trap("SIGINT") {
count.sort{|a, b|
a[1] <=> b[1]
}.each do |key, value|
print "#{key}: #{value}\n"
end
exit!
}
while line = gets
words = line.split
words.each do |word|
count[word] += 1
end
end
Reference to the documentation of Ruby Signal
Try Ctrl-D. Is this what you need?
count = Hash.new(0)
stop_condition = "\n"
until stop_condition == line = gets
words = line.split
words.each do |word|
count[word] += 1
end
end
Of course, you could use a break if line.chomp.empty? inside the while loop But I avoid it, as it really is an infinite loop that you know the condition of which you want to escape from. This also doesn't exit the program, just the loop.
controlc and controld are strange for users, and I would avoid needing to use those things for non-exceptional events.