Sentencia Switch for greater-than / less-than


Así que quiero usar una instrucción switch como esta:

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

Ahora sé que cualquiera de esas declaraciones (<1000) o (>1000 && <2000) no funcionará (por diferentes razones, obviamente). Lo que estoy pidiendo es la forma más eficiente de hacer precisamente eso. Odio usar sentencias 30 if, así que prefiero usar la sintaxis switch. ¿Hay algo que pueda hacer?

Author: switz, 2011-07-12

10 answers

Cuando miré las soluciones en las otras respuestas vi algunas cosas que sé que son malas para el rendimiento. Iba a ponerlos en un comentario, pero pensé que era mejor compararlo y compartir los resultados. Puedes probarlo tú mismo . A continuación se muestran mis resultados (ymmv) normalizados después de la operación más rápida en cada navegador (multiplique el tiempo 1.0 con el valor normalizado para obtener el tiempo absoluto en 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

Prueba donde se realizó en Windows 7 32bit con el siguientes versiones: Chrome 21.0.1180.89 m, Firefox 15.0, la Ópera 12.02, MSIE 9.0.8112, Safari 5.1.7. Node se ejecutó en una caja Linux de 64 bits debido a la resolución del temporizador en el nodo.js para Windows era 10ms en lugar de 1ms.

If-inmediata

Este es el más rápido en todos los entornos probados, excepto en ... redoble de tambores MSIE! (sorpresa, sorpresa). Esta es la forma recomendada de implementar se.

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

If-indirecto

Esta es una variante de switch-indirect-array pero if-instrucciones y realiza mucho más rápido que switch-indirect-array en casi todos los entornos probados.

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

Esto es bastante rápido en todos los entornos probados, y en realidad el más rápido en MSIE. Funciona cuando se puede hacer un cálculo para obtener un índice.

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

Rango de conmutación

Esto es aproximadamente de 6 a 40 veces más lento que el más rápido en todos los entornos probados excepto para la ópera, donde se tarda aproximadamente una vez y media más. Es lento porque el motor tiene que comparar el valor dos veces para cada caso. Sorprendentemente, se necesita Chrome casi 40 veces más tiempo para completar esto en comparación con la operación más rápida en Chrome, mientras que MSIE solo toma 6 veces más tiempo. Pero la diferencia de tiempo real fue de solo 74 ms a favor de MSIE en 1337 ms (!).

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

Esta es una variante de switch-range pero con solo una comparación por caso y por lo tanto más rápido, pero aún muy lento, excepto en la Ópera. El orden de la instrucción case es importante ya que el motor probará cada caso en el orden del código fuente ECMAScript262:5 12.11

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

Conmutador-matriz indirecta

En esta variante los rangos se almacenan en una matriz. Esto es lento en todos los entornos probados y muy lento en 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

Esta es una combinación de una búsqueda lineal de valores en una matriz, y el interruptor declaración con valores fijos. La razón por la que uno podría querer usar esto es cuando el los valores no se conocen hasta el tiempo de ejecución. Es lento en todos los entornos probados, y toma casi 10 veces más tiempo en 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

Esta es una variante de array-linear-switch, pero con una búsqueda binaria. Desafortunadamente es más lento que la búsqueda lineal. No se si es mi implementación o si la búsqueda lineal está más optimizada. También podría ser que el keyspace es pequeño.

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

Conclusión

Si el rendimiento es importante, use if-sentencias o switch con valores inmediatos.

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-07 05:21:30

Una alternativa:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-15 13:33:21
switch (Math.floor(scrollLeft/1000)) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

Solo funciona si tiene pasos regulares...

EDITAR: dado que esta solución sigue recibiendo votos positivos, debo aconsejar que la solución de mofolo es una manera mejor

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-06-05 11:35:02

Puede crear un objeto personalizado con los criterios y la función correspondientes a los criterios

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

Define funciones para lo que quieres hacer en estos casos (define function1, function2, etc.)

Y "evaluar" las reglas

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

Nota

Odio usar 30 if declaraciones

Muchas veces si las declaraciones son más fáciles de leer y mantener. Recomendaría lo anterior solo cuando tiene muchas condiciones y una posibilidad de lote de crecimiento en el futuro.

Actualizar
Como @Brad señaló en los comentarios, si las condiciones son mutuamente excluyentes (solo una de ellas puede ser verdadera a la vez), verificar el límite superior debería ser suficiente:

if(scrollLeft < oneRule.upperLimit)

siempre que las condiciones se definan en orden ascendente (primero la más baja, 0 to 1000, y luego 1000 to 2000 por ejemplo)

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-13 07:55:45

¿Qué estás haciendo exactamente en //do stuff?

Usted puede ser capaz de hacer algo como:

(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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 14:47:30

No probado e inseguro si esto funcionará, pero por qué no hacer unos cuantos if statements antes, para establecer variables para el 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-12 14:47:56

En mi caso (color-coding a percentage, nothing performance-critical), rápidamente escribí esto:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-28 09:09:21

Esta es otra opción:

     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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-07-19 13:18:34

Actualizando la respuesta aceptada (aún no se puede comentar). A partir del 1/12/16 utilizando la demo jsfiddle en chrome, switch-immediate es la solución más rápida.

Resultados: Resolución de tiempo: 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

Terminado

 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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-12 21:36:57

Odio usar 30 if declaraciones

Tuve la misma situación últimamente, así es como lo resolví:

Antes:

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

Después de:

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

Y si se establece "1, 2, 3, 4, 5" entonces puede ser aún más simple:

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/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-17 22:22:08