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/…
— csharpfolk

답변:


1032

펄처럼

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에는와 같이 continue및 에만 사용할 수 break있습니다 goto.


387
나는 자바 스크립트 내 삼년이되는 사용되는 곳을 볼 수없는 이유 WTF : / ..
— 살만 폰 압바스

39
MDN은 순전히 가독성을 위해 "라벨 사용을 피하십시오"라고 말합니다. 왜 '판독 가능'하지 않습니까? 물론 아무도 사용하지 않기 때문입니다. 그러나 왜 그것들을 사용하지 않습니까? ...
— XML

7
@Web_Designer 귀하의 의견이 오래되었다고 생각합니다. MDN 문서의 어느 곳에도 "레이블 사용을 피하십시오"라는 말이 없습니다. 댓글 수정 또는 삭제를 고려하십시오.
— Sean the Bean

8
@SeantheBean 완료. 이것은 더 간단한 대답처럼 보일하고 만 사용할 수 있기 때문에 남용 열리지 않습니다 continue및 break.
— 게리 윌러 비

29
@ JérémyPouyet-다운 투표에 대한 당신의 논리는 미쳤으며 보증되지 않습니다. OP의 질문에 완벽하게 대답합니다. 질문은 가독성에 대한 귀하의 의견과 관련이 없습니다. 커뮤니티 지원에 대한 귀하의 접근 방식을 재고하십시오.
— Dembinski

168

함수로 묶은 다음 그냥 return.


12
이 답변은 단순하고 우아한 방식으로 구현할 수 있기 때문에이 답변을 수락하기로 결정했습니다. 나는 절대적으로 GOTO를 싫어하고 나쁜 연습 ( 열 수 있음 )을 고려합니다 . Ephemient 's는 너무 가까이 있습니다. ; o)
— Gary Willoughby

16
GOTO는 구조화를 중단하지 않는 한 괜찮습니다. 그러나 각자 자신에게!
— ephemient

31
for 루프의 레이블은 구문을 제외하고는 GOTO와 공통점이 없습니다 . 그것들은 단순히 외부 루프에서 벗어나는 문제입니다. 가장 안쪽 루프를 끊는 데 아무런 문제가 없습니까? 그렇다면 왜 외부 루프를 끊는 데 문제가 있습니까?
— John Smith

11
다른 답변을 받아들이십시오. Andrew Hedges의 의견이 아니라면 (btw.) 감사합니다. 아, 자바 스크립트에는 그 기능이 없습니다. 그리고 커뮤니티의 많은 사람들이 의견을 간과하고 동일하게 생각할 수 있습니다.
— John Smith

11
왜 스택 오버플로에 커뮤니티가 명백히 잘못된 답변을 무시할 수있는 기능이 없습니까? : /
— Matt Huggins

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 구현은 이전 행의 끝에 콜론을 삽입 할 수 있기 때문에 여는 중괄호는 새 행에 없어야합니다.
— Evgeny

21
@Evgeny : 일부 JavaScript 스타일 가이드는 중괄호를 열어 같은 줄로 이동해야하지만 새 줄로 바꾸는 것은 올바르지 않으며 인터프리터가 세미콜론을 모호하게 삽입 할 위험이 없습니다. ASI의 동작은 잘 정의되어 있으며 여기에는 적용되지 않습니다.
— Jason Suárez

9
이 접근법에서 지옥에 대해 언급하십시오. 여기서 무슨 일이 일어나고 있는지 분명하지 않습니다.
— Qix-모니카는

1
좋고 간단한 대답. CPU 집약적 루프 (함수 사용에 문제가 있음)를 변형시키지 않거나 레이블을 사용하지 않기 때문에 답으로 간주해야합니다. :)
— Girish Sortur

2
뭔가 빠졌을 수도 있지만 내부 루프의 문제를 해결하기 위해 반복을 끝내야하는 문제를 해결 하려면 z와 y를 설정 한 직후 break또는 안에 넣을 수 continue있습니까? 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수행되는 abort경우 매번 값을 확인하면서 나머지 10 개의 반복을 계속 실행합니다 . 이것은 10 회 반복에 대한 성능 문제는 아니지만 10,000과 관련이 있습니다.
— Robusto

7
아니요, 두 루프에서 빠져 나옵니다. 여기는 바이올린을 보여줍니다 . 어떤 조건을 설정하든 관계가 충족되면 종료됩니다.
— zord December

4
최적화는 중단을 추가하는 것입니다. 중단 후 설정 = true; 최종 루프에서! abort 조건 확인을 제거합니다.
— xer21

1
나는 이것을 좋아하지만 일반적인 의미에서 불필요한 처리를 많이 할 것이라고 생각합니다. 즉 abort, 모든 반복자 평가 및 표현 의 각 반복에 대해 . 미세하지만, 문제가 될 수 gazillion 반복 거대한 루프 수 있습니다 간단한 시나리오에서
— Z. Khullah

1
단일 부울 값을 10000 번 확인하는 것이 빠르거나 느린 지에 대해 실제로 논쟁하고 있습니까? 1 억 번 시도 /
— sibs

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가 받고있는
— 것이라고

18
이는 루프가 클 경우 상당한 런타임 비용을 추가합니다. Javascript 인터프리터 / 컴파일러 (또는 요즘 "컴퓨터")에 의해 함수에 대한 새로운 실행 컨텍스트가 작성되어야하고 (GC가 어느 시점에서 해제해야 함) 매번.
— Mörre

2
예상치 못한 이상한 일이 발생할 수 있기 때문에 이것은 실제로 매우 위험합니다. 특히 var로 작성된 클로저로 인해 x루프 내의 논리가 나중에 x를 참조하는 경우 (예 : 나중에 저장 및 실행되는 내부 익명 함수를 정의하는 경우) x의 값은 모든 값이됩니다. 함수가 정의 된 색인이 아니라 루프 의 끝에 있었습니다. (계속)
— devios1

1
이 문제를 해결하려면 x익명 함수에 매개 변수로 매개 변수 를 전달 하여 새 복사본을 생성 한 다음 해당 시점부터 변경되지 않으므로 클로저로 참조 할 수 있습니다 . 요컨대, 나는 ephemient의 대답을 추천합니다.
— devios1

2
또한 가독성은 완전한 쓰레기라고 생각합니다. 이것은 라벨보다 더 모호합니다. 아무도 사용하지 않기 때문에 레이블은 읽을 수없는 것으로 만 표시됩니다 .
— Qix-MONICA가

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 나는 충분히 동의 할 수 없다! 그것은 자바 스크립트가 break 2;PHP에서와 같이 단순히 구문을 가지고 있지 않은 수치 입니다. 루프 레이블, 함수, if-else 검사, 루프 변수의 템퍼링 / 블 래스팅 없음-구문 만 정리하십시오!
— Jay Dadhania

1
예 4는
— 훌륭합니다

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
Drakes의 대답 은 더 간결하고 명확한 방식으로 동일한 논리를 가지고 있다고 생각 합니다.
— 엔지니어 토스트

절대적으로 훌륭합니다!
— geoyws

3

Coffeescript를 사용하면 편리한 "do"키워드가있어 익명 함수를 쉽게 정의하고 즉시 실행할 수 있습니다.

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

... "반환"을 사용하여 루프에서 벗어날 수 있습니다.


이것은 동일하지 않습니다. 내 원래 예제에는 for두 개가 아닌 세 개의 루프가 있습니다.
— Gary Willoughby

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가 이미 언급 했지만 아래 예제 (자바 스크립트)가 있습니다.

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

이러한 유형의 시나리오 (대부분의 경우)에 더 많은 시간이 걸리기 때문에 투표했습니다.
— Cody

-4

가장 좋은 방법은
-1) 첫 번째와 두 번째 루프에서 사용되는 두 배열을 정렬합니다.
2) 항목이 일치하면 내부 루프를 끊고 색인 값을 유지하십시오.
3) 다음 반복을 시작할 때 홀드 인덱스 값으로 내부 루프를 시작하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.