JavaScriptでネストされたループを解除する最良の方法は何ですか?


448

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.
         }
      }
   }
}

ループとコードブロックから抜け出す良い例を次に示します。marcin
chwedczuk.github.io

回答:


1031

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
            }
        }
    }

EMCA-262セクション12.12で定義されています。[MDNドキュメント]

Cとは異なり、Javascriptにはないので、これらのラベルはcontinueandにのみ使用breakできますgoto


387
WTFがJavaScriptを使用して3年間のどこかでこれを見たことがないのはなぜですか:/ ..
Salman von Abbas

39
MDNは、単に読みやすさを理由に「ラベルの使用を避ける」と述べています。なぜ「読めない」のですか?もちろん、誰も使っていないからです。しかし、なぜそれらを使用しないのですか?...
XML

7
@Web_Designerコメントは古くなっています。MDNドキュメントのどこにも「ラベルの使用を避ける」と書かれていません。コメントの修正または削除を検討してください。
Sean the Bean

8
@SeantheBean完了。これはより簡単な答えのように思えますがcontinue、とでのみ利用できるため、乱用の余地はありませんbreak
Gary Willoughby

29
@JérémyPouyet-反対投票の論理は狂っており、保証されていません。それはOPの質問に完全に答えます。質問は読みやすさに関するあなたの意見とは関係ありません。コミュニティを支援するためのアプローチを再検討してください。
デンビンスキー2017年

168

それを関数にラップしてから、単にreturn


12
シンプルでエレガントな方法で実装できるため、この回答を受け入れることにしました。私はGOTOを絶対に嫌い、彼らの悪い習慣(開くことができる)を考えます、Ephemientは1に近すぎます。; o)
Gary Willoughby、

16
IMO、GOTOは、構造化を壊さない限り問題ありません。しかし、それぞれに!
2008年

31
forループのラベルは、構文を除いて、GOTOとの共通点はまったくありません。それらは単に外側のループから抜け出すための問題です。あなたは最も内側のループを壊すことに問題はありませんか?では、なぜ外側のループを壊すことに問題があるのですか?
John Smith

11
他の回答を受け入れることを検討してください。Andrew Hedgesのコメント(ありがとうございます)がなければ、ああ、javascriptにはその機能はありません。そして、私はコミュニティの多くがコメントを見落とし、同じように考えるかもしれないに違いない。
John Smith

11
Stack Overflowには、明らかに間違って選択された回答をコミュニティがオーバーライドできる機能がないのはなぜですか?:/
マットハギンズ2014

85

私はパーティーに少し遅れましたが、以下はGOTO /ラベルまたは関数ラッピングを使用しない、言語に依存しないアプローチです。

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
      }
   }
}

上向きにそれは自然に流れます、そしてそれは非GOTO群衆を喜ばせるべきです。欠点として、内側のループは終了する前に現在の反復を完了する必要があるため、一部のシナリオでは適用できない場合があります。


2
js実装は前の行の終わりにコロンを挿入する可能性があるため、開始中括弧は新しい行に置くべきではありません。
エフゲニー

21
@Evgeny:一部のJavaScriptスタイルガイドでは、同じ行に中かっこを開く必要がありますが、新しい行に中かっこを付けることは正しく、通訳が曖昧にセミコロンを挿入する危険はありません。ASIの動作は明確に定義されており、ここでは適用されません。
JasonSuárez2013年

9
このアプローチの地獄をコメントアウトしてください。ここで何が行われているのかすぐにはわかりません。
Qix-モニカは2014年

1
素晴らしくシンプルな答え。これは、CPU集中型ループに負担をかけない(これは関数の使用に関する問題です)か、通常は読み込めないか、または何とかして使用するべきではないラベルを使用しないため、回答と見なす必要があります。:)
Girish Sortur

2
私は何かが足りないかもしれませんが、内部ループがその反復を完了する必要があるという問題を回避するには、a breakまたはcontinuezとyを設定した直後に入れることができますか?forループの条件を使用してキックアウトするというアイデアが好きです。独自の方法でエレガント。
Ben Sutton

76

これは本当に古いトピックだと思いますが、私の標準的なアプローチはまだここにないので、将来のGoogle社員のために投稿すると思いました。

var a, b, abort = false;
for (a = 0; a < 10 && !abort; a++) {
    for (b = 0; b < 10 && !abort; b++) {
        if (condition) {
            doSomeThing();
            abort = true;
        }
    }
}

2
場合conditionに評価されtrue、ネストされたループの最初の繰り返しで、あなたはまだチェックし、10回の反復の残りの部分を介して実行abort値たびに。これは10回の反復ではパフォーマンスの問題ではありませんが、たとえば10,000の場合は問題になります。
Robusto

7
いいえ、両方のループから出ています。これが実演のフィドルです。設定した条件に関係なく、条件が満たされた後に終了します。
zord

4
最適化は、ブレークを追加することです。abort = trueを設定した後。最後のループから!abort条件チェックを削除します。
xer21

1
私はこれが好きですが、一般的な意味では、多くの不要な処理を行うことになると思いますabort。つまり、すべての反復子の評価と式の反復ごとに。単純なシナリオでは問題ないかもしれませんが、ガジリオンの反復がある巨大なループでは問題になる可能性があります
Z. Khullah

1
1つのブール値を10000回チェックするのが速いのか遅いのか、本当に議論していますか?1億回/ため息
fabspro

40
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
}

どのようだ?:)


2
私は、これはSWILLIAMSができたものである考え出し
harley.333

18
これにより、ループが大きい場合、ランタイムコストが大幅に増加します。Javascriptインタープリター/コンパイラー(または最近では「コンプリーター」、両方の組み合わせ)によって、関数の新しい実行コンテキストを作成する必要があります(ある時点でGCによって解放されます)。毎回。
Mörre

2
これは実際には非常に危険です。予想外の奇妙なことが発生する可能性があるためです。特に、var xで作成されたクロージャーのため、ループ内のいずれかのロジックが後でxを参照する場合(たとえば、保存されて後で実行される内部の無名関数を定義する場合)、xの値は、ループの最後にあり、関数が定義されたインデックスではありませんでした。(続き)
devios1

1
これを回避xするには、無名関数にパラメーターとして渡して、その新しいコピーを作成する必要があります。その後、そのコピーは変更されないため、クロージャーとして参照できます。要するに、私はエフェミエントの答えをお勧めします。
devios1

2
同様に、私は読みやすさは完全にがらくただと思います。これはレーベルよりも曖昧です。ラベルは誰も使用していないため、判読不能と見なされます。
Qix-モニカは2014年

39

非常にシンプル:

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;
}

これは実際には最高の機能であり、スケーリングしない関数であり、すべてのforループをラップしますが、スケーリングしない場合、つまり、読み取りとデバッグが困難になります...これは素晴らしいです。vars loop1、loop2、loop3を宣言し、最後に小さなステートメントを追加するだけです。また、複数のループを解除するには、次のようなことを行う必要がありますloop1=loop2=false;
Muhammad Umer

22

JavaScriptでネストされたループを抜け出す5つの方法を次に示します。

1)親のループを最後に設定します

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

2)ラベルを使用する

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

3)変数を使用

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)自己実行機能を使用する

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

5)通常の関数を使用する

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

1
@Wyck私は十分に同意することはできません!これは残念なことです。JavaScriptにはbreak 2;、PHPのような構文はありません。ループラベルなし、関数なし、if-elseチェックなし、ループ変数の/ブラストによる調整なし-単純な構文!
ジェイダダニア

1
例4は気の利いた
leroyjenkinss24

14

ブレーク、アボートフラグ、追加の条件チェックをまったく使用しないのはどうですか。このバージョンNumber.MAX_VALUEは、条件が満たされたときにループ変数を爆破する(それらを作る)だけで、すべてのループをエレガントに終了させます。

// 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
    }
  }
}

デクリメント型のネストされたループについても同様の答えがありましたが、これは、単純なループの各ループの終了値を考慮する必要なしに、インクリメント型のネストされたループに対して機能します。

もう一つの例:

// 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
        }
      }
    }
  }
}

4

ループを限界までプッシュするのはどうですか

    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;
            }
         }
       }
     }

1
ドレイクスの答えは、より簡潔で明確な方法で同じロジックを持っていると思います。
エンジニアトースト

絶対に素晴らしい!
geoyws 2017

3

Coffeescriptを使用する場合、無名関数を定義してすぐに実行するのを容易にする便利な「do」キーワードがあります。

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

...ループから抜け出すには、単に「return」を使用します。


これは同じではありません。私の元の例には、for2つではなく3つのループがあります。
Gary Willoughby 2017

2

関数型プログラミングのアプローチを示すと思いました。私のソリューションのように、入れ子になったArray.prototype.some()および/またはArray.prototype.every()関数から抜け出すことができます。このアプローチの追加の利点はObject.keys()「for-inループがプロトタイプチェーンのプロパティも列挙する」のに対して、オブジェクト自体の列挙可能なプロパティのみを列挙すること です。

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;
    }

見出し/アイテムの反復を減らすソリューション:

    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

すでにswilliamsによってすでに言及されていますが、以下の例(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

うーん、10歳のパーティーへようこそ。

条件を入れてみませんか?

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
        }
    }
}

このようにしたいときに停止します

私の場合、Typescriptを使用して、配列を通過して条件が満たされたときに停止するsome()を使用できます。したがって、私のコードは次のようになります。

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

このように、条件が満たされた直後にループが停止しました

注意:このコードはTypeScriptで実行されます


-3
XXX.Validation = function() {
    var ok = false;
loop:
    do {
        for (...) {
            while (...) {
                if (...) {
                    break loop; // Exist the outermost do-while loop
                }
                if (...) {
                    continue; // skips current iteration in the while loop
                }
            }
        }
        if (...) {
            break loop;
        }
        if (...) {
            break loop;
        }
        if (...) {
            break loop;
        }
        if (...) {
            break loop;
        }
        ok = true;
        break;
    } while(true);
    CleanupAndCallbackBeforeReturning(ok);
    return ok;
};

9
これはオリジナルよりも混乱します。
Cristiano Fontes

21
ポストモダンの詩のように
Digerkam 2013年

(ほとんどの場合)do whileがこのタイプのシナリオになりつつあるため、投票されました。
Cody

-4

最良の方法は
-1)最初と2番目のループで使用される両方の配列をソートします。
2)アイテムが一致した場合、内部ループを中断し、インデックス値を保持します。
3)次の反復を開始するときに、保持インデックス値で内部ループを開始します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.