web-dev-qa-db-fra.com

Comment rompre avec les boucles imbriquées dans Ruby?

supposons le code Ruby suivant:

bank.branches do |branch|
  branch.employees.each do |employee|
    NEXT BRANCH if employee.name = "John Doe"
  end
end

NEXT BRANCH est bien sûr un pseudocode. y a-t-il un moyen de sortir d'une boucle parent, comme en Perl, par exemple (en utilisant des étiquettes de boucle)?

merci d'avance.

44
crlsrns

Catch et lancer pourrait être ce que vous cherchez:

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
82
steenslag

Il n'y a pas de moyen intégré pour sortir des blocs sans leur consentement. Vous devrez juste faire quelque chose comme:

bank.branches do |branch|
  break unless branch.employees.each do |employee|
    break if employee.name == "John Doe"
  end
end
16
Chuck
while c1
 while c2
    # execute code
    do_break = true if need_to_break_out_of_parent_loop
 end
 break if do_break
end
5
Anno2001

Mon impulsion serait de déplacer les blocs imbriqués dans une méthode, avec un return à la place de 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
4
Stovey

D'autres publications ont référencé une idée similaire à la création d'une variable "switch". Voir ci-dessous pour un exemple clair de son fonctionnement. Gardez à l'esprit que la seconde boucle sera toujours en cours d'exécution jusqu'à ce qu'elle atteigne la fin du tableau d'employés, mais n'exécutera aucun code après l'inversion du commutateur. Ce n'est pas la manière optimale de procéder car cela peut être inutilement coûteux en temps si votre groupe d'employés est grand. 

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

Une fois le commutateur inversé, la matrice interne ne sera plus active et la boucle parente passera à la branche suivante avec la réinitialisation du commutateur. Il est évident que davantage de commutateurs peuvent être utilisés pour des cas plus complexes.

0
MusicIsFreedom

Edit: L’effet souhaité peut être obtenu beaucoup plus simplement en appelant break dans la boucle interne (ne met fin à cette boucle):

bank.branches do |branch|
  branch.employees.each do |employee|
    break if employee.name = "John Doe"
  end
end

Voici ce que @steenslag était en train de rédiger avec 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

Votre exemple est donc:

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
0
Epigene