Apa cara terbaik untuk melepaskan diri dari loop bersarang di JavaScript?

448

Apa cara terbaik untuk memecah dari loop bersarang di 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.
         }
      }
   }
}
Gary Willoughby
sumber
Berikut adalah contoh yang baik untuk keluar dari loop dan keluar dari blok kode: marcin-chwedczuk.github.io/…
csharpfolk

Jawaban:

1031

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

sebagaimana didefinisikan dalam EMCA-262 bagian 12.12. [MDN Documents]

Tidak seperti C, label ini hanya dapat digunakan untuk continuedan break, karena Javascript tidak memiliki goto.

singkat
sumber
387
WTF mengapa saya belum melihat ini digunakan di suatu tempat dalam 3 tahun saya dengan JavaScript: / ..
Salman von Abbas
39
MDN mengatakan "hindari menggunakan label" murni atas dasar keterbacaan. Mengapa itu tidak 'terbaca'? Karena tidak ada yang menggunakannya, tentu saja. Tapi mengapa mereka tidak menggunakannya? ...
XML
7
@ Web_Designer Saya yakin komentar Anda sudah kedaluwarsa. Tidak ada dalam dokumen MDN yang mengatakan "hindari menggunakan label". Harap pertimbangkan untuk merevisi atau menghapus komentar Anda.
Sean the Bean
8
@ SeantheBean Selesai. Ini sepertinya jawaban yang lebih langsung dan tidak terbuka untuk penyalahgunaan karena hanya tersedia untuk continuedan break.
Gary Willoughby
29
@ JérémyPouyet - Logika Anda untuk memilih tidak sah dan tidak beralasan. Ini menjawab pertanyaan OP dengan sempurna. Pertanyaannya tidak berkaitan dengan pendapat Anda tentang keterbacaan. Harap pertimbangkan kembali pendekatan Anda untuk membantu komunitas.
The Dembinski
168

Bungkus itu dalam suatu fungsi dan kemudian adil return.

swilliams
sumber
12
Saya memilih untuk menerima jawaban ini karena sederhana dan dapat diimplementasikan dengan cara yang elegan. Saya benar-benar membenci GOTO dan menganggapnya sebagai praktik buruk ( bisa dibuka ), Ephemient terlalu dekat. ; o)
Gary Willoughby
16
IMO, GOTO baik-baik saja asalkan tidak melanggar penataan. Tetapi untuk masing-masing mereka sendiri!
ephemient
31
Label aktif untuk loop sama sekali tidak memiliki kesamaan dengan GOTO kecuali sintaksisnya. Mereka hanyalah masalah untuk istirahat dari loop luar. Anda tidak memiliki masalah dengan memecahkan loop terdalam, bukan? jadi mengapa Anda memiliki masalah dengan melanggar loop luar?
John Smith
11
Silakan pertimbangkan menerima jawaban lain. Kalau bukan karena komentar Andrew Hedges (terima kasih btw.), Saya akan berpikir: ah, jadi javascript tidak memiliki fitur itu. Dan saya bertaruh banyak orang di komunitas mungkin mengabaikan komentar dan berpikir sama.
John Smith
11
Mengapa Stack Overflow tidak memiliki fitur untuk membiarkan komunitas mengabaikan jawaban yang dipilih dengan jelas salah? : /
Matt Huggins
85

Saya sedikit terlambat ke pesta tetapi berikut ini adalah pendekatan agnostik bahasa yang tidak menggunakan GOTO / label atau pembungkus fungsi:

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

Pada sisi atas mengalir secara alami yang seharusnya menyenangkan kerumunan non-GOTO. Pada sisi negatifnya, loop dalam perlu menyelesaikan iterasi saat ini sebelum mengakhiri sehingga mungkin tidak berlaku dalam beberapa skenario.

aleemb
sumber
2
brace pembuka tidak boleh pada baris baru, karena implementasi js dapat memasukkan titik dua di akhir baris sebelumnya.
Evgeny
21
@ Evgeny: sementara beberapa panduan gaya JavaScript meminta pembukaan kurung untuk masuk pada baris yang sama, tidaklah salah untuk memilikinya di baris baru dan tidak ada bahaya penerjemah secara ambigu memasukkan tanda titik koma. Perilaku ASI didefinisikan dengan baik dan tidak berlaku di sini.
Jason Suárez
9
Pastikan untuk mengomentari pendekatan ini. Tidak segera jelas apa yang terjadi di sini.
Qix - MONICA DISEBUTKAN
1
Jawaban yang bagus dan sederhana. Ini harus dianggap sebagai jawaban, karena tidak menegangkan loop intensif CPU (yang merupakan masalah dengan menggunakan fungsi) atau tidak menggunakan label, yang biasanya tidak dapat dibaca atau tidak boleh digunakan seperti yang dikatakan beberapa orang. :)
Girish Sortur
2
Saya mungkin kehilangan sesuatu, tetapi untuk menyelesaikan masalah loop batin harus menyelesaikan iterasi yang bisa Anda masukkan ke dalam breakatau continuesegera setelah Anda mengatur z dan y? Saya suka ide menggunakan kondisi forloop untuk menendang keluar. Elegan dengan caranya sendiri.
Ben Sutton
76

Saya menyadari bahwa ini adalah topik yang sangat lama, tetapi karena pendekatan standar saya belum ada di sini, saya pikir saya mempostingnya untuk googler masa depan.

var a, b, abort = false;
for (a = 0; a < 10 && !abort; a++) {
    for (b = 0; b < 10 && !abort; b++) {
        if (condition) {
            doSomeThing();
            abort = true;
        }
    }
}
zord
sumber
2
Jika conditiondievaluasi truepada iterasi pertama dari loop bersarang, Anda masih menjalankan sisa 10 iterasi, memeriksa abortnilai setiap kali. Ini bukan masalah kinerja untuk 10 iterasi, tetapi itu akan dengan, katakanlah, 10.000.
Robusto
7
Tidak, itu keluar dari kedua loop. Ini biola yang mendemonstrasikan . Tidak peduli kondisi apa yang Anda tetapkan, itu keluar setelah bertemu.
zord
4
Optimalisasi akan menambah jeda; setelah pengaturan batalkan = benar; dan menghapus! batalkan cek kondisi dari loop terakhir.
xer21
1
Saya suka ini, tetapi saya pikir secara umum Anda akan membuat banyak pemrosesan yang tidak perlu - yaitu, untuk setiap iterasi setiap iterator mengevaluasi abortdan ekspresi. Dalam skenario sederhana yang mungkin baik-baik saja, tetapi untuk loop besar dengan iterasi trilyun yang bisa menjadi masalah
Z. Khullah
1
Apakah kalian benar-benar berdebat tentang apakah memeriksa nilai boolean tunggal 10.000 kali cepat atau lambat? coba 100 juta kali / desah
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
}

Bagaimana dengan itu? :)

harley.333
sumber
2
Saya pikir inilah yang ingin dicapai oleh
swilliams
18
Ini menambahkan biaya runtime yang signifikan jika loop besar - konteks eksekusi baru untuk fungsi harus dibuat (dan pada titik tertentu dibebaskan oleh GC) oleh penerjemah / kompiler Javascript (atau, "compreter" hari ini, gabungan keduanya) SETIAP SAAT.
Mörre
2
Ini sebenarnya cukup berbahaya karena beberapa hal aneh dapat terjadi yang mungkin tidak Anda duga. Khususnya, karena penutupan yang dibuat dengan var x, jika ada logika di dalam loop yang merujuk x pada titik waktu berikutnya (misalnya ia mendefinisikan fungsi anonim dalam yang disimpan dan dieksekusi kemudian), nilai untuk x akan menjadi apa pun berada di akhir loop, bukan indeks fungsi yang didefinisikan selama. (lanjutan)
devios1
1
Untuk menyiasatinya, Anda harus meneruskan xsebagai parameter ke fungsi anonim Anda sehingga membuat salinan baru, yang kemudian dapat direferensikan sebagai penutupan karena tidak akan berubah sejak saat itu. Singkatnya, saya merekomendasikan jawaban ephemient.
devios1
2
Juga, saya pikir hal keterbacaan adalah omong kosong. Ini jauh lebih kabur daripada label. Label hanya dilihat sebagai tidak dapat dibaca karena tidak ada yang pernah menggunakannya.
Qix - MONICA DISEBUTKAN
39

Cukup sederhana:

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;
}
akinuri
sumber
Saya setuju ini sebenarnya yang terbaik, fungsi yang tidak skala, membungkus semua untuk loop jika juga tidak skala yaitu membuatnya sulit untuk membaca dan men-debug .... yang ini luar biasa. Anda bisa mendeklarasikan vars loop1, loop2, loop3, dan menambahkan sedikit statement di akhir. Juga untuk memutus banyak loop, Anda perlu melakukan sesuatu sepertiloop1=loop2=false;
Muhammad Umer
22

Berikut adalah lima cara untuk keluar dari loop bersarang di JavaScript:

1) Setel perulangan ke akhir

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

2) Gunakan label

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

3) Gunakan variabel

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) Gunakan fungsi self-executing

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

5) Gunakan fungsi biasa

function nested_loops()
{
    for (i = 0; i < 5; i++)
    {
        for (j = 0; j < 5; j++)
        {
             if (j === 2)
                 return;
        }
    }
}
nested_loops();
Dan Bray
sumber
1
@ Ya Tuhan, saya tidak cukup setuju! Sayang javascript tidak hanya memiliki sintaksis break 2;seperti yang kita miliki di PHP. Tidak ada label loop, tidak ada fungsi, tidak ada pemeriksaan if-else, tidak ada tempering dengan / peledakan variabel loop - cukup bersihkan sintaks!
Jay Dadhania
1
Contoh 4 adalah bagus
leroyjenkinss24
14

Bagaimana kalau menggunakan tidak ada istirahat sama sekali, tidak ada membatalkan bendera, dan tidak ada pemeriksaan kondisi tambahan. Versi ini hanya menghancurkan variabel loop (membuatnya Number.MAX_VALUE) ketika kondisi terpenuhi dan memaksa semua loop untuk mengakhiri dengan elegan.

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

Ada jawaban ish yang serupa untuk loop bertipe tipe decrementing, tetapi ini berfungsi untuk loop bertingkat tipe incrementing tanpa perlu mempertimbangkan nilai terminasi setiap loop untuk loop sederhana.

Contoh lain:

// 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
        }
      }
    }
  }
}
Drakes
sumber
4

Bagaimana dengan mendorong loop ke batas akhir mereka

    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;
            }
         }
       }
     }
pengguna889030
sumber
1
Saya pikir jawaban Drakes memiliki logika yang sama dengan cara yang lebih ringkas dan jelas.
Engineer Toast
benar-benar brilian!
geoyws
3

Jika Anda menggunakan Coffeescript, ada kata kunci "do" yang nyaman yang membuatnya lebih mudah untuk didefinisikan dan segera menjalankan fungsi anonim:

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

... jadi Anda cukup menggunakan "kembali" untuk keluar dari loop.

Nick Perkins
sumber
Ini tidak sama. Contoh asli saya memiliki tiga forloop, bukan dua.
Gary Willoughby
2

Saya pikir saya akan menunjukkan pendekatan pemrograman fungsional. Anda dapat keluar dari fungsi Array.prototype.some () dan / atau Array.prototype.every (), seperti di solusi saya. Manfaat tambahan dari pendekatan ini adalah bahwa Object.keys()enumerasi hanya properti enumerable objek sendiri, sedangkan "for-in loop menyebutkan properti dalam rantai prototipe juga" .

Dekat dengan solusi 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;
    }

Solusi yang mengurangi iterasi pada Judul / Item:

    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;
            }
        });
    });
Zachary Ryan Smith
sumber
2

Sudah disebutkan sebelumnya oleh swilliams , tetapi dengan contoh di bawah ini (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);
}
Matt Borja
sumber
0

Hmmm hai ke pesta 10 tahun?

Mengapa tidak menaruh beberapa syarat untuk Anda?

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

Seperti ini, Anda berhenti ketika Anda mau

Dalam kasus saya, menggunakan Typescript, kita dapat menggunakan beberapa () yang melewati array dan berhenti ketika kondisi terpenuhi Jadi kode saya menjadi seperti ini:

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

Seperti ini, loop berhenti tepat setelah kondisi terpenuhi

Pengingat: Kode ini dijalankan dalam TypeScript

Azutanguy
sumber
-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;
};
Triqui
sumber
9
Ini terlihat lebih membingungkan daripada yang asli.
Cristiano Fontes
21
Seperti puisi postmodern
Digerkam
Memilih karena do do sementara lebih mengarah ke jenis skenario ini (dalam kebanyakan kasus).
Cody
-4

cara terbaik adalah -
1) Urutkan kedua array yang digunakan di loop pertama dan kedua.
2) jika item cocok maka pecahkan loop dalam dan tahan nilai indeks.
3) ketika mulai iterasi berikutnya mulai loop dalam dengan nilai indeks tahan.

Deepak Karma
sumber