web-dev-qa-db-fra.com

Quel est le meilleur moyen de sortir des boucles imbriquées?

Quel est le meilleur moyen de rompre avec les boucles imbriquées en Javascript?

//Write the links to the page.
for (var x = 0; x < Args.length; x++)
{
   for (var Heading in Navigation.Headings)
   {
      for (var Item in Navigation.Headings[Heading])
      {
         if (Args[x] == Navigation.Headings[Heading][Item].Name)
         {
            document.write("<a href=\"" 
               + Navigation.Headings[Heading][Item].URL + "\">" 
               + Navigation.Headings[Heading][Item].Name + "</a> : ");
            break; // <---HERE, I need to break out of two loops.
         }
      }
   }
}
343
Gary Willoughby

Tout comme Perl,

loop1:
    for (var i in set1) {
loop2:
        for (var j in set2) {
loop3:
            for (var k in set3) {
                break loop2;  // breaks out of loop3 and loop2
            }
        }
    }

comme défini dans la section 12.12 du document EMCA-262. [Documents MDN]

Contrairement à C, ces étiquettes ne peuvent être utilisées que pour continue et break , car Javascript n'a pas goto.

820
ephemient

Enveloppez cela dans une fonction puis return.

138
swilliams

Je suis un peu en retard à la fête, mais voici une approche indépendante de la langue qui n'utilise ni GOTO/labels ni fonctions encapsulées:

for (var x = Set1.length; x > 0; x--)
{
   for (var y = Set2.length; y > 0; y--)
   {
      for (var z = Set3.length; z > 0; z--)
      {
          z = y = -1; // terminates second loop
          // z = y = x = -1; // terminate first loop
      }
   }
}

En revanche, cela coule naturellement, ce qui devrait plaire à la foule des non-GOTO. En revanche, la boucle interne doit terminer l'itération en cours avant la fin, de sorte qu'elle pourrait ne pas être applicable dans certains scénarios.

73
aleemb

Je réalise que c’est un sujet très ancien, mais comme mon approche standard n’est pas encore définie, j’ai pensé le poster pour les futurs googlers.

var a, b, abort = false;
for (a = 0; a < 10 && !abort; a++) {
    for (b = 0; b < 10 && !abort; b++) {
        if (condition) {
            doSomeThing();
            abort = true;
        }
    }
}
65
zord
var str = "";
for (var x = 0; x < 3; x++) {
    (function() {  // here's an anonymous function
        for (var y = 0; y < 3; y++) {
            for (var z = 0; z < 3; z++) {
                // you have access to 'x' because of closures
                str += "x=" + x + "  y=" + y + "  z=" + z + "<br />";
                if (x == z && z == 2) {
                    return;
                }
            }
        }
    })();  // here, you execute your anonymous function
}

Comment ça :)

37
harley.333

assez facile

var a=[1,2,3];
var b=[4,5,6];
var breakCheck1=false;

for (var i in a){
    for (var j in b){
        breakCheck1=true;
        break;
    }
    if (breakCheck1) {break;}
}
33
Paul Di Biase

Pourquoi ne pas utiliser aucune pause du tout, aucun indicateur d'abandon et aucune vérification de condition supplémentaire. Cette version analyse uniquement les variables de la boucle (les rend Number.MAX_VALUE) lorsque la condition est remplie et force toutes les boucles à se terminer élégamment.

// No breaks needed
for (var i = 0; i < 10; i++) {
  for (var j = 0; j < 10; j++) {
    if (condition) {
      console.log("condition met");
      i = j = Number.MAX_VALUE; // Blast the loop variables
    }
  }
}

Il y avait une réponse similaire pour les boucles imbriquées de type décrémentant, mais cela fonctionne pour les boucles imbriquées de type incrémenté sans qu'il soit nécessaire de prendre en compte la valeur de terminaison de chaque boucle pour les boucles simples.

Un autre exemple:

// No breaks needed
for (var i = 0; i < 89; i++) {
  for (var j = 0; j < 1002; j++) {
    for (var k = 0; k < 16; k++) {
      for (var l = 0; l < 2382; l++) {
        if (condition) {
          console.log("condition met");
          i = j = k = l = Number.MAX_VALUE; // Blast the loop variables
        }
      }
    }
  }
}
13
Drakes

Que diriez-vous de pousser les boucles à leurs limites

    for(var a=0; a<data_a.length; a++){
       for(var b=0; b<data_b.length; b++){
           for(var c=0; c<data_c.length; c++){
              for(var d=0; d<data_d.length; d++){
                 a =  data_a.length;
                 b =  data_b.length;
                 c =  data_b.length;
                 d =  data_d.length;
            }
         }
       }
     }
5
user889030

Si vous utilisez Coffeescript, il existe un mot-clé "do" qui facilite la définition et l'exécution immédiate d'une fonction anonyme:

do ->
  for a in first_loop
    for b in second_loop
      if condition(...)
        return

... afin que vous puissiez simplement utiliser "return" pour sortir des boucles.

3
Nick Perkins

Je pensais montrer une approche de programmation fonctionnelle. Vous pouvez sortir des fonctions imbriquées Array.prototype.some () et/ou Array.prototype.every (), comme dans mes solutions. Un avantage supplémentaire de cette approche est que Object.keys() énumère uniquement les propriétés énumérables propres à un objet, tandis que "une boucle for-in énumère également les propriétés de la chaîne de prototypes" .

Proche de la solution de l'OP:

    Args.forEach(function (arg) {
        // This guard is not necessary,
        // since writing an empty string to document would not change it.
        if (!getAnchorTag(arg))
            return;

        document.write(getAnchorTag(arg));
    });

    function getAnchorTag (name) {
        var res = '';

        Object.keys(Navigation.Headings).some(function (Heading) {
            return Object.keys(Navigation.Headings[Heading]).some(function (Item) {
                if (name == Navigation.Headings[Heading][Item].Name) {
                    res = ("<a href=\""
                                 + Navigation.Headings[Heading][Item].URL + "\">"
                                 + Navigation.Headings[Heading][Item].Name + "</a> : ");
                    return true;
                }
            });
        });

        return res;
    }

Solution qui réduit les itérations sur les titres/éléments:

    var remainingArgs = Args.slice(0);

    Object.keys(Navigation.Headings).some(function (Heading) {
        return Object.keys(Navigation.Headings[Heading]).some(function (Item) {
            var i = remainingArgs.indexOf(Navigation.Headings[Heading][Item].Name);

            if (i === -1)
                return;

            document.write("<a href=\""
                                         + Navigation.Headings[Heading][Item].URL + "\">"
                                         + Navigation.Headings[Heading][Item].Name + "</a> : ");
            remainingArgs.splice(i, 1);

            if (remainingArgs.length === 0)
                return true;
            }
        });
    });
2
Zachary Ryan Smith

Hmmm salut à la fête de 10 ans?

Pourquoi ne pas mettre une condition dans votre pour?

var condition = true
for (var i = 0 ; i < Args.length && condition ; i++) {
    for (var j = 0 ; j < Args[i].length && condition ; j++) {
        if (Args[i].obj[j] == "[condition]") {
            condition = false
        }
    }
}

Comme ça tu t'arrêtes quand tu veux

Dans mon cas, en utilisant TypeScript, nous pouvons utiliser une méthode () qui parcourt le tableau et s’arrête lorsque la condition est remplie. Ainsi, mon code devient comme ceci:

Args.some((listObj) => {
    return listObj.some((obj) => {
        return !(obj == "[condition]")
    })
})

Comme cela, la boucle s'est arrêtée juste après que la condition soit remplie

Rappel: Ce code est exécuté en TypeScript

0
Azutanguy

Voici cinq manières de sortir des boucles imbriquées en JavaScript:

1) Place la boucle parent (s) à la fin

for (i = 0; i < 5; i++)
{
    for (j = 0; j < 5; j++)
    {
        if (j === 2)
        {
            i = 5;
            break;
        }
    }
}

2) Utiliser l'étiquette

exit_loops:
for (i = 0; i < 5; i++)
{
    for (j = 0; j < 5; j++)
    {
        if (j === 2)
            break exit_loops;
    }
}

3) Utiliser variable

var exit_loops = false;
for (i = 0; i < 5; i++)
{
    for (j = 0; j < 5; j++)
    {
        if (j === 2)
        {
            exit_loops = true;
            break;
        }
    }
    if (exit_loops)
        break;
}

4) Utiliser la fonction d'exécution automatique

(function()
{
    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
             if (j === 2)
                 return;
        }
    }
})();

5) Utiliser la fonction régulière

function nested_loops()
{
    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
             if (j === 2)
                 return;
        }
    }
}
nested_loops();
0
Dan Bray

Déjà mentionné précédemment par swilliams , mais avec un exemple ci-dessous (Javascript):

// Function wrapping inner for loop
function CriteriaMatch(record, criteria) {
  for (var k in criteria) {
    if (!(k in record))
      return false;

    if (record[k] != criteria[k])
      return false;
  }

  return true;
}

// Outer for loop implementing continue if inner for loop returns false
var result = [];

for (var i = 0; i < _table.length; i++) {
  var r = _table[i];

  if (!CriteriaMatch(r[i], criteria))
    continue;

  result.add(r);
}
0
Original Poster