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 완료. 이것은 더 간단한 대답처럼 보일하고 만 사용할 수 있기 때문에 남용 열리지 않습니다 continuebreak.
게리 윌러 비

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.