Switch statement for greater-than/less-than

Więc chcę użyć instrukcji switch takiej jak Ta:

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

Teraz wiem, że jedno z tych stwierdzeń (<1000) lub (>1000 && <2000) nie zadziała (oczywiście z różnych powodów). To, o co proszę, to najskuteczniejszy sposób, aby to zrobić. Nienawidzę używać 30 if Instrukcji, więc wolałbym użyć składni switch. Mogę coś zrobić?

Author: switz, 2011-07-12

10 answers

Kiedy spojrzałem na rozwiązania w innych odpowiedziach zobaczyłem pewne rzeczy, które Wiem, że są złe dla wydajności. Miałem zamiar umieścić je w komentarzu, ale pomyślałem, że lepiej jest porównać go i podzielić się wynikami. Możesz przetestować go samodzielnie. Poniżej znajdują się moje wyniki (ymmv) znormalizowane po najszybszej operacji w każdej przeglądarce (pomnóż czas 1.0 z znormalizowaną wartością, aby uzyskać czas bezwzględny w ms).

                    Chrome  Firefox Opera   MSIE    Safari  Node
-------------------------------------------------------------------
1.0 time               37ms    73ms    68ms   184ms    73ms    21ms
if-immediate            1.0     1.0     1.0     2.6     1.0     1.0
if-indirect             1.2     1.8     3.3     3.8     2.6     1.0
switch-immediate        2.0     1.1     2.0     1.0     2.8     1.3
switch-range           38.1    10.6     2.6     7.3    20.9    10.4
switch-range2          31.9     8.3     2.0     4.5     9.5     6.9
switch-indirect-array  35.2     9.6     4.2     5.5    10.7     8.6
array-linear-switch     3.6     4.1     4.5    10.0     4.7     2.7
array-binary-switch     7.8     6.7     9.5    16.0    15.0     4.9

Test gdzie wykonywane na Windows 7 32bit z following versions: Chrome 21.0.1180.89 m, Firefox 15.0, Opera 12.02, MSIE 9.0.8112, Safari 5.1.7 . Node został uruchomiony na 64-bitowym Linuksie, ponieważ rozdzielczość timera na węźle.js Dla Windows był 10ms zamiast 1ms.

If-immediate

Jest to najszybsze we wszystkich testowanych środowiskach, z wyjątkiem ... MSIE! (niespodzianka, niespodzianka). Jest to zalecany sposób realizacji to.

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

If-indirect

Jest to wariant switch-indirect-array, ale zamiast tego z if-statements i działa znacznie szybciej niż switch-indirect-array w prawie wszystkich testowanych środowiskach.

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

Switch-immediate

Jest to dość szybkie we wszystkich testowanych środowiskach, a właściwie najszybsze w MSIE. Działa, gdy można wykonać obliczenia, aby uzyskać indeks.

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

Switch-range

Jest to około 6 do 40 razy wolniejsze niż najszybsze we wszystkich testowanych środowiskach z wyjątkiem dla Opery, gdzie trwa około półtora raza dłużej. Jest powolny, ponieważ silnik musi porównać wartość dwukrotnie dla każdego przypadku. Zaskakujące jest to, że Chrome zajmuje prawie 40 razy więcej czasu w porównaniu z najszybszą operacją w Chrome, podczas gdy MSIE zajmuje tylko 6 razy więcej czasu. Ale rzeczywista różnica czasu była tylko 74ms na korzyść MSIE w 1337ms (!).

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

Switch-range2

Jest to wariant switch-range, ale z tylko jednym porównaniem na przypadek i dlatego szybciej, ale nadal bardzo wolno, z wyjątkiem Opery. Kolejność instrukcji case jest ważna, ponieważ silnik będzie testował każdy przypadek w kolejności kodu źródłowego ECMAScript262:5 12.11

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

Switch-indirect-array

W tym wariancie zakresy są przechowywane w tablicy. Jest to powolne we wszystkich testowanych środowiskach i bardzo powolne w 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;
}

Array-linear-search

Jest to kombinacja liniowego wyszukiwania wartości w tablicy i przełącznika oświadczenie z stałe wartości. Powodem, dla którego ktoś może chcieć tego użyć, jest to, że wartości są znane dopiero w trybie runtime. Jest powolny w każdym testowanym środowisku i trwa prawie 10 razy dłużej w MSIE.

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-binary-switch

Jest to wariant array-linear-switch, ale z przeszukiwaniem binarnym. Niestety jest to wolniejsze niż wyszukiwanie liniowe. Nie wiem, czy to moja implementacja, czy wyszukiwanie liniowe jest bardziej zoptymalizowane. Możliwe, że przestrzeń kluczy jest zbyt mała.

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

Podsumowanie

Jeśli wydajność jest ważna, użyj instrukcji if-lub switch z natychmiastowymi wartościami.

 546
Author: some,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-07 05:21:30

Alternatywa:

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

Demo: http://jsfiddle.net/UWYzr/

 81
Author: labue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-15 13:33:21
switch (Math.floor(scrollLeft/1000)) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

Działa tylko wtedy, gdy masz regularne kroki...

EDIT: skoro to rozwiązanie ciągle się poprawia, muszę doradzić, że rozwiązanie mofolo jest o wiele lepsze

 20
Author: IcanDivideBy0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-05 11:35:02

Możesz utworzyć własny obiekt z kryteriami i funkcją odpowiadającą kryteriom

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

Zdefiniuj funkcje dla tego, co chcesz zrobić w tych przypadkach (zdefiniuj function 1, function 2 itp.)

I "oceń" Zasady

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

Uwaga

Nienawidzę używać 30 wyrażeń if

Wiele razy, jeśli stwierdzenia są łatwiejsze do odczytania i utrzymania. Polecam powyższe tylko wtedy, gdy masz dużo warunków i możliwość dużo wzrostu w przyszłości.

Aktualizacja
Jak zauważył @Brad w komentarzach, jeśli warunki wzajemnie się wykluczają (tylko jeden z nich może być prawdziwy na raz), sprawdzenie górnej granicy powinno być wystarczające:

if(scrollLeft < oneRule.upperLimit)

pod warunkiem , że warunki są zdefiniowane w porządku rosnącym (najpierw najniższy, 0 to 1000, a następnie 1000 to 2000 na przykład)

 6
Author: Nivas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-13 07:55:45

Co dokładnie robisz w //do stuff?

Możesz zrobić coś takiego:

(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc. 
 3
Author: Igor,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-12 14:47:30

Nieprzetestowane i niepewne, czy to zadziała, ale dlaczego nie zrobić kilka if statements wcześniej, aby ustawić zmienne dla 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;
}
 3
Author: Jason Gennaro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-07-12 14:47:56

W moim przypadku (kodowanie kolorami procent, nic krytycznego dla wydajności), szybko napisałem to:

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
Author: grebenyuksv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-28 09:09:21

Jest to inna opcja:

     switch (true) {
         case (value > 100):
             //do stuff
             break;
         case (value <= 100)&&(value > 75):
             //do stuff
             break;
         case (value < 50):
            //do stuff
             break;
     }
 0
Author: Pablo Claus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-19 13:18:34

Aktualizacja zaakceptowanej odpowiedzi (nie mogę jeszcze skomentować). Od 1/12/16 używając demo jsfiddle w chrome, switch-immediate jest najszybszym rozwiązaniem.

Wyniki: Rozdzielczość czasowa: 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

Zakończone

 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
 0
Author: jeffhale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-12 21:36:57

I hate using 30 if statements

Ostatnio miałem taką samą sytuację, tak to rozwiązałem:

Przed:

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

Po:

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

I jeśli ustawisz "1, 2, 3, 4, 5" wtedy może być jeszcze prościej:

var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
 0
Author: Martin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-17 22:22:08