9
votes

Briser des boucles imbriquées

Quelqu'un peut-il me dire comment briser la boucle principale quand j'ai des boucles imbriquées?
Exemple *:

/*Main loop*/
for(int y = 0; y < 100; y+=10)
{
    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 60) 
        { 
            //Break the main loop 
        }
    }
}


2 commentaires

Si possible, placez-le à l'intérieur d'une méthode distincte que vous pouvez simplement revenir, ce qui sera court-circuiter les boucles.


ALLER À! Hé, attends - où vous allez? Bonjour?


13 Réponses :


7
votes

Utilisez un drapeau pour signaler la terminaison:

for(int y = 0; y < 100; y+=10)
{
     bool flag = false;
     for(int x = 0; x < 100; x += 10)
     {
        if (x == 56)
        {
           flag = true;
           break;
        }
     }

     if(flag) break;
}


7 commentaires

C'est une façon verbeuse de le faire. Vous pouvez simplement vérifier le drapeau dans le pour boucle conditionnelle.


C'est une bonne chose à ce sujet, c'est qu'il est très facile de comprendre pour les autres programmeurs: zéro facteur surprise.


@Jon, je ne pense pas que ce soit un style propre d'avoir plus d'une condition à l'intérieur d'un.


Je préfère aller sur cette solution de contournement. (Bien sûr seulement si refactoring n'est pas bon choix)


@cjrh pensez-vous réellement? Pour moi, pour un, pensez que goto est beaucoup plus évident ici - sans parler plus efficacement.


@Fge: tbh, lorsque les boucles ont besoin de résiliation plus tôt que leurs limites suggérées, je soupçonne que cela devrait être une condition exceptionnelle si vous attrapez mon sens. De ce point de vue, goto et exceptions font exactement la même chose.


C'est fait avec des drapeaux comme ça à Pascal .. Je pensais que c # peut avoir quelque chose d'intelligent comme Java. Mais je vais l'utiliser .. J'ai essayé la déclaration Goto, mais cela n'a pas fonctionné correctement.



11
votes
  • refacteur afin que vous n'ayez pas besoin de quitter des boucles imbriquées de cette manière.
    Utilisation de retour est souvent possible en mettant les boucles dans une fonction séparée.
  • Utilisez goto .
  • Utilisez un drapeau (laid)

5 commentaires

Personne ne devrait jamais utiliser goto dans une langue de haut niveau.


IMO Drapeau-Break-Check-ChreeFlag-Break est encore plus laid que GoTo. Mais bien sûr, le refactoring est le choix préféré dans la mesure du possible.


GOTO est parfaitement légitime et c'est la meilleure utilisation pour cela, il est plus efficace que l'une des autres options présentées. Aucun programmeur ne devrait vivre par des règles telles que "N'utiliser jamais goto ", mais vous devez savoir quand à utiliser goto .


@Aiabstract Ceci est exactement Le type de situation où goto est la meilleure réponse. Arrêtez de régurgiter le N'utilisez jamais goto déchets que vous avez été enseigné. Utilisez le bon outil dans la bonne situation.


@Rob: la bonne réponse est du refacteur. Je n'aime pas l'option Breakflag-Breakflag-Breakflag-Breakflag-Breakflag. Et ce n'est pas la régurgitation, c'est à propos de l'exactitude. :)



3
votes

Souvent, il est préférable de mettre cela dans une fonction distincte et de faire un «retour» xxx


2 commentaires

Dans les vraies boucles imbriquées, je calcule quelque chose. Si je dois les transmettre à une méthode, ce sera vraiment laid!


Dépend de la façon dont vous le faites ... Souvent, ces choses deviennent désordonnées parce que les gens ont beaucoup de variables et les n'ont pas encapsulés dans une structure. Idéalement, vous vous retrouvez avec beaucoup de fonctions qui fonctionnent sur une structure. (OO simplifié).



5
votes

Certaines personnes me timer pour suggérer l'utilisation de la relève goto , mais la rupture de plusieurs boucles est l'un des endroits qu'il peut être très utile (et efficace): xxx < / pré>


6 commentaires

Ils sont terribles lorsqu'ils sont utilisés par de jeunes codeurs et entraînent un code spaghetti. En tant que développeur, vous devez utiliser les outils à votre disposition, et Goto est le moyen le plus efficace de sortir de plusieurs boucles imbriquées.


Je suis d'accord avec le préalable au sujet du code spaghetti, j'utilise toujours une pause ou un retour


+1 - Je suis avec vous - c'est l'un des rares endroits où goto rend les choses meilleures, pas pire. La restructuration pour éviter les boucles imbriquées serait idéale, mais si ce n'est pas une option, alors goto loin!


La solution simple de Hogan d'une variable booléenne supplémentaire est presque tout aussi efficace, et beaucoup plus maintenue et claire à d'autres programmeurs.


Je ne vois pas comment il est plus maintenu. S'il y avait plus de boucles impliquées, vous devez modifier plus de code, cela ne nécessite pas non plus une variable supplémentaire.


Pouvez-vous élaborer un peu? Vous avez décidé de poster une version mise à jour de votre code pour que nous puissions voir ce qui se passe.



0
votes
/*Main loop*/
for(int y = 0; y < 100; y+=10)
{
    bool makeMeBreak = false;

    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56) 
        { 

            //Break the main loop 
            makeMeBreak = true;
            break;
        }
    }
    if (makeMeBreak) break;
}

0 commentaires

18
votes

goto !

Je ne comprends pas ce meme persistant qui dit que goto est considéré comme "nocif". Lorsqu'il est utilisé correctement, il est très puissant et c'est un tel cas.


5 commentaires

Un jour, lorsque quelqu'un vous remet trois de trois décennies, un code de fortrain, poivré avec des gotos mal écrites et vous dit de réparer les bugs et de découvrir que c'est impossible au refacteur, vous comprendrez. Les meilleurs programmeurs peuvent faire de la magie avec goto. Le pire peut faire un grand mal.


Les meilleurs programmeurs peuvent utiliser goto sans causer de chagrin ce que ce soit et crée le code le plus efficace dans le processus.


+1, briser des boucles imbriquées est l'une des rares utilisations acceptables de goto imo. Beaucoup plus propre que d'utiliser un drapeau.


@cjrh et c'est pourquoi il a dit bien utilisé, c'est très puissant et c'est un tel cas. . Outil droit pour la bonne situation.


Je ne vois tout simplement pas pourquoi certaines personnes ici préféreraient utiliser un drapeau qu'un goto dans ce cas.



2
votes

Je ne sais pas s'il y a un moyen de sortir des boucles imbriquées en C #, mais permettez-moi de suggérer une solution de contournement.

Vous pouvez lancer la boucle principale dans une fonction et revenir de cette fonction. Vous pouvez renvoyer false; pour indiquer une pause prématurée et renvoyer true; pour indiquer que la boucle passait jusqu'à présent, si cela importe.


0 commentaires

0
votes

Il n'y a pas de bonne réponse générique. La «bonne façon» dépend du vrai problème. La meilleure façon peut être de mettre la boucle extérieure dans une fonction puis d'utiliser retour; pour sortir de celui-ci. Il pourrait être x = 100; y = 100; . Cela pourrait être fait = true; . Heck, il pourrait même être goto (blindé).


0 commentaires

2
votes

Les drapeaux, comme suggéré dans les commentaires, sont probablement la meilleure méthode: xxx


1 commentaires

Ce n'est que si court car il n'y a aucun code après la boucle interne et après le si. Avec ce code, vous devez ajouter deux pauses et un chèque.



0
votes

pas conseillé mais vous pouvez utiliser goto code>. Voir Ceci .

public class GotoTest1
{
    static void Main()
    {
        int x = 200, y = 4;
        int count = 0;
        string[,] array = new string[x, y];

        // Initialize the array:
        for (int i = 0; i < x; i++)

            for (int j = 0; j < y; j++)
                array[i, j] = (++count).ToString();

        // Read input:
        Console.Write("Enter the number to search for: ");

        // Input a string:
        string myNumber = Console.ReadLine();

        // Search:
        for (int i = 0; i < x; i++)
        {
            for (int j = 0; j < y; j++)
            {
                if (array[i, j].Equals(myNumber))
                {
                    goto Found;
                }
            }
        }

        Console.WriteLine("The number {0} was not found.", myNumber);
        goto Finish;

    Found:
        Console.WriteLine("The number {0} is found.", myNumber);

    Finish:
        Console.WriteLine("End of search.");


        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/*
Sample Input: 44

Sample Output
Enter the number to search for: 44
The number 44 is found.
End of search.
*/


0 commentaires

0
votes

Depuis, comme vous l'avez mentionné, il n'y a pas d'étiquettes sur la commande Break code>, vous pouvez faire quelque chose comme ceci:

/*Main loop*/
bool fFound;
for(int y = 0; y < 100 && !fFound; y+=10)
{
    /*Sub loop*/
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56) 
        { 
            //Break the main loop 
            fFound = true;
            break; //Break inner loop
        }
    }
}


0 commentaires

0
votes

Comme d'autres l'ont dit, la réponse "correcte" dépend du problème que vous résolvez. Si vous le pouvez, la rupture en pièces plus petites est la voie préférée. Quelque chose sur ce modèle:

object MainLoop ()
{
    object result = null;
    for(int y = 0; y < 100; y+=10)
    {
        result = SubLoop(y);
        if (result != null)
        {
            break;
        }
    }
    return result;
}

object SubLoop (int y)
{
    object result = null;
    for (int x = 0; x < 100; x += 10)
    {
        if(x == 56)
        {
            result = objectInstance;
            break;
        }
    }
    return result;
}


0 commentaires

0
votes

J'ai utilisé LINQ pour rassembler les objets intéressants, puis effectué les opérations sur les résultats de la requête LINQ. Enlevant ainsi des boucles imbriquées et remplaçant avec une boucle.


0 commentaires