rails - ¿Cómo romper con los bucles anidados en Ruby?
manejo de objetos en ruby (6)
Mi impulso sería mover los bloques anidados en un método, con un return
en lugar de la break
.
def find_branch_and_employee_by_name(bank,emp_name)
bank.branches.each do |branch|
branch.employees.each do |employee|
return([branch,employee]) if employee.name == emp_name
end
end
nil # employee wasn''t found
end
asumir el siguiente código ruby:
bank.branches do |branch|
branch.employees.each do |employee|
NEXT BRANCH if employee.name = "John Doe"
end
end
NEXT BRANCH es, por supuesto, pseudocódigo. ¿Hay alguna forma de que pueda salir de un bucle principal, como se puede hacer en Perl, por ejemplo (mediante el uso de etiquetas de bucle)?
gracias por adelantado.
No existe una forma integrada de romper bloques que contienen sin su consentimiento. Tendrás que hacer algo como:
bank.branches do |branch|
break unless branch.employees.each do |employee|
break if employee.name == "John Doe"
end
end
Otras publicaciones han hecho referencia a una idea similar a la creación de una variable "cambiar". Vea a continuación un claro ejemplo de cómo funciona. Tenga en cuenta que el segundo bucle seguirá ejecutándose hasta que llegue al final de la matriz de empleados, pero no ejecutará ningún código una vez que se haya volteado el interruptor. Esta no es la forma óptima de hacerlo, ya que puede ser innecesariamente costoso si su matriz de empleados es grande.
def workforce
bank.branches do |branch|
switch = 0
branch.employees.each do |employee|
if switch == 1
next
end
if employee.name = "John Doe"
switch = 1
end
end
end
Después de que el interruptor se voltea, la matriz interna ya no estará activa y el bucle principal se moverá a la siguiente bifurcación con el restablecimiento del interruptor. Obviamente, se pueden usar más interruptores para casos más complejos.
Atrapar y arrojar puede ser lo que estás buscando:
bank.branches do |branch|
catch :missingyear do #:missingyear acts as a label
branch.employees.each do |employee|
(2000..2011).each do |year|
throw :missingyear unless something #break out of two loops
end
end
end #You end up here if :missingyear is thrown
end
Editar: El efecto deseado, resulta, se puede lograr de una forma mucho más simple llamando a la ruptura dentro del ciclo interno (solo terminará ese ciclo):
bank.branches do |branch|
branch.employees.each do |employee|
break if employee.name = "John Doe"
end
end
Esto es lo que @steenslag estaba escribiendo con Ruby begin-rescue-end block:
letters = [%w(a b c),%w(d e f),%w(g h i)]
# => [["a", "b", "c"], ["d", "e", "f"], ["g", "h", "i"]]
letters.each do |trine|
begin
trine.each do |letter|
raise "Breaking out of inner cycle." if letter == "e"
puts letter
end
rescue
next
end
end
# => abcdghi
Entonces tu ejemplo es:
bank.branches do |branch|
branch.employees.each do |employee|
begin
raise "Breaking out of inner cycle." if employee.name = "John Doe"
rescue
next
end
end
end
while c1
while c2
# execute code
do_break = true if need_to_break_out_of_parent_loop
end
break if do_break
end