보다 큼 /보다 큼에 대한 스위치 설명


230

그래서 다음과 같이 switch 문을 사용하고 싶습니다.

switch (scrollLeft) {
  case (<1000):
   //do stuff
   break;
  case (>1000 && <2000):
   //do stuff
   break;
}

이제 나는 그 진술 ( <1000) 또는 ( >1000 && <2000) 중 하나가 작동하지 않는다는 것을 알고 있습니다 (다른 이유로, 분명히). 내가 묻는 것은 그 일을하는 가장 효율적인 방법입니다. 나는 30 개의 if문장을 사용하는 것을 싫어 하므로 스위치 구문을 사용하고 싶습니다. 내가 할 수있는 일이 있습니까?


5
당신의 단계는 규칙적입니까? scrollLeft를 1000으로 나누면 1, 2, 3으로 전환 할 수 있습니다.
IcanDivideBy0

어쩌면 해당 연산과 조건 범위를 매핑하는 정렬 된 배열을 만들고 이진 검색을 적용 할 수 있습니다. 아니면 조건이 충분히 정규 경우, 직접 부를 수있는 your_mapper_object[scrollLeft / SOME_CONST], 가정은 your_mapper_object같은 것입니다 {1: some_func, 2: another_func, ...}. 이 경우 스위치를 사용할 수도 있습니다.
Overmind Jiang

답변:


731

다른 답변의 솔루션을 볼 때 성능이 좋지 않은 것을 알았습니다. 나는 그것들을 의견에 넣을 것이지만 그것을 벤치마킹하고 결과를 공유하는 것이 더 낫다고 생각했다. 직접 테스트 할 수 있습니다 . 아래는 각 브라우저에서 가장 빠른 작업 후 표준화 된 결과 (ymmv)입니다 (1.0 시간에 정규화 된 값을 곱하여 절대 시간 (ms)).

                    Chrome Firefox Opera MSIE Safari 노드
-------------------------------------------------- -----------------
1.0 시간 37ms 73ms 68ms 184ms 73ms 21ms
즉각적인 경우 1.0 1.0 1.0 2.6 1.0 1.0
간접적 인 경우 1.2 1.8 3.3 3.8 2.6 1.0
스위치 즉시 2.0 1.1 2.0 1.0 2.8 1.3
스위치 범위 38.1 10.6 2.6 7.3 20.9 10.4
스위치 범위 2 31.9 8.3 2.0 4.5 9.5 6.9
스위치 간접 어레이 35.2 9.6 4.2 5.5 10.7 8.6
어레이 선형 스위치 3.6 4.1 4.5 10.0 4.7 2.7
어레이 이진 스위치 7.8 6.7 9.5 16.0 15.0 4.9

Chrome 21.0.1180.89m , Firefox 15.0 , Opera 12.02 , MSIE 9.0.8112 , Safari 5.1.7 과 같은 버전으로 Windows 7 32 비트에서 수행되는 위치에서 테스트하십시오 . Windows 용 Node.js의 타이머 해상도가 1ms가 아니라 10ms이므로 Linux 64 비트 상자에서 노드 가 실행되었습니다.

즉시

이것은 드럼 롤 MSIE를 제외하고 모든 테스트 된 환경에서 가장 빠릅니다 ! (놀람, 놀라움). 이를 구현하기 위해 권장되는 방법입니다.

if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else

간접적 인 경우

이것은 -statement를 대신 한 변형 switch-indirect-array이지만 거의 모든 테스트 된 환경에서 if보다 훨씬 빠르게 수행 switch-indirect-array됩니다.

values=[
   1000,  2000, ... 30000
];
if (val < values[0]) { /* do something */ } else
if (val < values[1]) { /* do something */ } else
...
if (val < values[29]) { /* do something */ } else

스위치 즉시

이것은 테스트 된 모든 환경에서 매우 빠르며 실제로 MSIE에서 가장 빠릅니다. 계산을 수행하여 색인을 얻을 수있을 때 작동합니다.

switch (Math.floor(val/1000)) {
  case 0: /* do something */ break;
  case 1: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

스위치 범위

이는 약 1.5 배의 시간이 걸리는 Opera를 제외하고는 모든 테스트 된 환경에서 가장 빠른 것보다 약 6 ~ 40 배 느립니다. 엔진이 각 경우에 대해 값을 두 번 비교해야하기 때문에 속도가 느립니다. 놀랍게도 Chrome에서 가장 빠른 작업에 비해 Chrome을 완료하는 데 거의 40 배가 더 걸리지 만 MSIE는 6 배만 걸립니다. 그러나 실제 시차는 1337ms (!)에서 MSIE에 유리한 74ms에 불과했습니다.

switch (true) {
  case (0 <= val &&  val < 1000): /* do something */ break;
  case (1000 <= val &&  val < 2000): /* do something */ break;
  ...
  case (29000 <= val &&  val < 30000): /* do something */ break;
}

스위치 범위 2

이는 switch-range사례 당 하나의 비교 만 있는 변형 이지만 더 빠르지 만 Opera를 제외하고는 여전히 매우 느립니다. 엔진이 소스 코드 순서로 각 사례를 테스트하므로 사례 설명의 순서는 중요합니다 . ECMAScript262 : 5 12.11

switch (true) {
  case (val < 1000): /* do something */ break;
  case (val < 2000): /* do something */ break;
  ...
  case (val < 30000): /* do something */ break;
}

스위치 간접 배열

이 변형에서 범위는 배열에 저장됩니다. 테스트 된 모든 환경에서 느리고 Chrome에서는 매우 느립니다.

values=[1000,  2000 ... 29000, 30000];

switch(true) {
  case (val < values[0]): /* do something */ break;
  case (val < values[1]): /* do something */ break;
  ...
  case (val < values[29]): /* do something */ break;
}

배열 선형 검색

이것은 배열에서 값의 선형 검색과 고정 값을 가진 switch 문의 조합입니다. 이것을 사용하려는 이유는 런타임까지 값을 알 수 없기 때문입니다. 테스트 된 모든 환경에서 속도가 느리고 MSIE에서 거의 10 배의 시간이 걸립니다.

values=[1000,  2000 ... 29000, 30000];

for (sidx=0, slen=values.length; sidx < slen; ++sidx) {
  if (val < values[sidx]) break;
}

switch (sidx) {
  case 0: /* do something */ break;
  case 1: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

어레이 이진 스위치

이것은 array-linear-switch이진 검색 의 변형입니다 . 불행히도 선형 검색보다 느립니다. 구현인지 선형 검색이 더 최적화되어 있는지 알 수 없습니다. 키 공간이 작을 수도 있습니다.

values=[0, 1000,  2000 ... 29000, 30000];

while(range) {
  range = Math.floor( (smax - smin) / 2 );
  sidx = smin + range;
  if ( val < values[sidx] ) { smax = sidx; } else { smin = sidx; }
}

switch (sidx) {
  case 0: /* do something */ break;
  ...
  case 29: /* do something */ break;
}

결론

성능이 중요한 경우- if문 또는 switch즉시 값을 사용하십시오.


128
이처럼 자세하고 깔끔한 구조로 답을 보는 것은 드 rare니다. 빅 +1
Rick Donohoe

10
이 문제의 성능 측면에 대한 설명은 Big +1입니다!
Zoltán Schmidt

16
이것이 stackoverflow가 가장 적합한 답변 중 하나 인 이유입니다. 이것은 "영원한"대답, 훌륭한 직업이며 jsfiddle에 감사드립니다!
Jessy

1
GRT 정보 및 explainination
JayKandari

3
정말 자세한 답변을 +2 할 수 있기를 바랍니다!
Kaspar Lee

96

대안:

var scrollleft = 1000;
switch (true)
{
    case (scrollleft > 1000):
      alert('gt');
      break;
    case (scrollleft <= 1000):
      alert('lt');
      break; 
}

데모 : http://jsfiddle.net/UWYzr/


4
이것은 더 가치있는 솔루션입니다. +1
IcanDivideBy0

1
이것과 동일하지 if(...) else if(...)않습니까? 이것은 피할 수는 if있지만 나에게 대체하는 것처럼 들리지는 않습니다.
pimvdb

7
코드는 우아하지만 성능이 저하됩니다. Chrome에서 if-statement를 사용하는 것보다 거의 30 배 느립니다 . 내보기 여기에 대답을
일부

1
그러나 처리되는 데이터가 크지 않고 단일 사용자 입력의 유효성을 검사하는 것과 같이 해당 기능 만 적용되는 경우 이러한 성능 저하가 무시할 수 있습니다. 그런 경우 성능보다는 가독성이 선택됩니다.
Jesús Franco

1
이것이 바로 내가 찾던 것입니다. 감사!
Ami Schreiber

23
switch (Math.floor(scrollLeft/1000)) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

정기적 인 단계가있는 경우에만 작동합니다 ...

편집 :이 솔루션은 계속 upvotes 얻기 때문에 mofolo의 솔루션 이 더 나은 방법 이라는 조언을해야합니다


1
그건 Math.round(scrollLeft/1000)그렇고
switz

@Switz-999 <1000은 사례 0에 해당하지만 Math.round (999/1000)은 사례 1에 해당한다는 것을 명심하십시오. 또한 위의 오타가있는 경우 1은> 1000이 아니라> = 1000입니다. .
Igor

mofolo 솔루션의 문제는 Chrome에서 IcanDivideBy0보다 약 30 배 느리다는 것입니다. 아래 내 답변을 참조하십시오.

6

기준과 기준에 해당하는 기능으로 사용자 정의 객체를 생성 할 수 있습니다

var rules = [{ lowerLimit: 0,    upperLimit: 1000, action: function1 }, 
             { lowerLimit: 1000, upperLimit: 2000, action: function2 }, 
             { lowerLimit: 2000, upperLimit: 3000, action: function3 }];

이 경우에 원하는 기능을 정의하십시오 (function1, function2 등 정의).

그리고 규칙을 "평가"

function applyRules(scrollLeft)
{
   for(var i=0; i>rules.length; i++)
   {
       var oneRule = rules[i];
       if(scrollLeft > oneRule.lowerLimit && scrollLeft < oneRule.upperLimit)
       {
          oneRule.action();
       }
   }
}

노트

나는 30 if 문을 사용하는 것을 싫어

진술을 읽고 유지하기가 더 쉬운 경우가 많습니다. 난 당신이 많은 조건있는 경우에만 위의를 추천 하고 가능성 의 많은 미래의 성장을.

업데이트
로 @ 브래드 충분합니다 상한을 확인, 조건이 상호 배타적 인 경우 (단지 그들 중 하나는 한 번에 사실 수), 주석을 지적했다 :

if(scrollLeft < oneRule.upperLimit)

제공 조건이 오름차순으로 정의되는 (제 1 최저 한 0 to 10001000 to 2000예를 들어)


action=function1-이것들은 콜론이 아니어야합니까? ;-)-제거 프로세스로 인해 두 그룹에 속할 수 없기 때문에 상한을 갖도록 리팩토링 할 수도 있습니다.
브래드 크리스티

@Brad Christie 물론
Nivas

@ 브래드, 아니 그건 내 의도가 아니었고, 당신은 옳았습니다. 상한은 충분해야합니다. 업데이트로 추가 할
예정입니다

나는이 하나의 간결하고 깨끗한 +1 찾을
pimvdb

3

정확히 뭐하는 //do stuff거야?

다음과 같은 작업을 수행 할 수 있습니다.

(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc. 

3

테스트를 수행하고 이것이 작동하는지 확실하지 않지만, 몇 가지 if statements를 수행하여에 대한 변수를 설정하십시오 switch statement.

var small, big;

if(scrollLeft < 1000){
    //add some token to the page
    //call it small
}


switch (//reference token/) {
  case (small):
   //do stuff
   break;
  case (big):
   //do stuff;
   break;
}

2

이것은 또 다른 옵션입니다.

     switch (true) {
         case (value > 100):
             //do stuff
             break;
         case (value <= 100)&&(value > 75):
             //do stuff
             break;
         case (value < 50):
            //do stuff
             break;
     }

1

허용 된 답변 업데이트 중 (아직 댓글을 달 수 없음) 크롬에서 데모 jsfiddle을 사용하는 1/12/16에서 switch-immediate가 가장 빠른 솔루션입니다.

결과 : 시간 분해능 : 1.33

   25ms "if-immediate" 150878146 
   29ms "if-indirect" 150878146
   24ms "switch-immediate" 150878146
   128ms "switch-range" 150878146
   45ms "switch-range2" 150878146
   47ms "switch-indirect-array" 150878146
   43ms "array-linear-switch" 150878146
   72ms "array-binary-switch" 150878146

끝마친

 1.04 (   25ms) if-immediate
 1.21 (   29ms) if-indirect
 1.00 (   24ms) switch-immediate
 5.33 (  128ms) switch-range
 1.88 (   45ms) switch-range2
 1.96 (   47ms) switch-indirect-array
 1.79 (   43ms) array-linear-switch
 3.00 (   72ms) array-binary-switch

-15ms "즉시"15ms "간접"15ms "스위치 즉시"37ms "스위치 범위"28ms "스위치 범위 2"35ms "스위치 간접 어레이"29ms "배열 선형 스위치" 62ms "배열 이진 스위치"완료 됨 즉시 1.00 (15ms) 즉시 1.00 (15ms) 간접이면 1.00 (15ms) 스위치 즉시 2.47 (37ms) 스위치 범위 1.87 (28ms) 스위치 범위 2 2.33 (35ms) 스위치- 간접 어레이 1.93 (29ms) 어레이 선형 스위치 4.13 (62ms) 어레이 바이너리 스위치 크롬 버전 48.0.2564.109 (64 비트) mac OS x 10.11.3
RenaissanceProgrammer

Mac OS x의 ATM Safari 9.X 및 Safari ios 9.3, "즉시"는 확실한 승자입니다
르네상스

1
1ms의 차이는 너무 적습니다. 각 테스트 실행에서보다 더 다양합니다. 요점은 다음과 같습니다. 의미있는 코딩 스타일을 사용하고 미세 최적화를 시도하지 마십시오.

1

필자의 경우 (비율 코딩, 성능에 중요한 것은 없음), 나는 이것을 다음과 같이 썼다.

function findColor(progress) {
    const thresholds = [30, 60];
    const colors = ["#90B451", "#F9A92F", "#90B451"];

    return colors.find((col, index) => {
        return index >= thresholds.length || progress < thresholds[index];
    });
}

1

나는 30 if 문을 사용하는 것을 싫어

나는 최근에 같은 상황을 겪었고, 그것이 내가 해결 한 방법입니다.

전에:

if(wind_speed >= 18) {
    scale = 5;
} else if(wind_speed >= 12) {
    scale = 4;
} else if(wind_speed >= 9) {
    scale = 3;
} else if(wind_speed >= 6) {
    scale = 2;
} else if(wind_speed >= 4) {
    scale = 1;
}

후:

var scales = [[4, 1], [6, 2], [9, 3], [12, 4], [18, 5]];
scales.forEach(function(el){if(wind_speed > el[0]) scale = el[1]});

"1, 2, 3, 4, 5"를 설정하면 훨씬 간단 해집니다.

var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.