web-dev-qa-db-fra.com

Instruction Switch pour plus que / moins que

donc je veux utiliser une instruction switch comme ceci:

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

Maintenant, je sais que l'une ou l'autre de ces déclarations (<1000) ou (>1000 && <2000) ne fonctionnera pas (pour des raisons différentes, évidemment). Ce que je demande, c’est le moyen le plus efficace de le faire. Je déteste utiliser 30 if instructions, je préfère donc utiliser la syntaxe switch. Y a-t-il quelque chose que je puisse faire?

202
switz

Quand j'ai regardé les solutions dans les autres réponses, j'ai vu des choses qui, je le sais, sont mauvaises pour la performance. J'allais les mettre dans un commentaire mais je pensais qu'il était préférable de le comparer et de partager les résultats. Vous pouvez le tester vous-même . Ci-dessous, mes résultats (ymmv) normalisés après l’opération la plus rapide dans chaque navigateur (multipliez le temps 1.0 par la valeur normalisée pour obtenir le temps absolu en ms).

 Chrome Firefox Opera MSIE Safari Node 
 ---------------------- --------------------------------------------- 
 1,0 heure 37 ms 73 ms 68 ms 184 ms 73 ms 21 ms 
 Si-immédiat 1.0 1.0 1.0 2.6 1.0 1.0 
 Si-indirect 1.2 1.8 3.3 3.8 3.8 1.0 
 Commutateur-immédiat 2.0 1.1 2.0 1.0 2.8 
 plage de commutation 38.1 10.6 2.6 7.3 20.9 10.4 
 plage de commutation2 31.9 8.3 2.0 4.5 9.5 6.9 
 matrice de commutation indirecte 35.2 9.6 4.2 5.5 10.7 8.6 
 matrice -linéaire-commutateur 3.6 4.1 4.5 10.0 4.7 2.7 
 tableau-commutateur-binaire 7.8 6.7 9.5 16.0 15.0 4.9 

Le test a été effectué sous Windows 7 32 bits avec les versions suivantes: Chrome 21.0.1180.89m , Firefox 15.0 , Opera 12.02 , MSIE 9.0.8112 , Safari 5.1.7 . Le noeud a été exécuté sur une boîte Linux 64 bits, car la résolution du temporisateur sur Node.js pour Windows était de 10 ms au lieu de 1 ms.

si-immédiat

C'est le plus rapide dans tous les environnements testés, sauf dans ... drumroll MSIE! (surprise Surprise). C'est le moyen recommandé pour le mettre en œuvre.

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

si-indirect

Ceci est une variante de switch-indirect-array mais avec les instructions if- et s'exécute beaucoup plus rapidement que switch-indirect-array dans presque tous les environnements testés.

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

commutateur immédiat

C'est assez rapide dans tous les environnements testés, et en fait le plus rapide dans MSIE. Cela fonctionne lorsque vous pouvez faire un calcul pour obtenir un index.

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

plage de commutation

Ceci est environ 6 à 40 fois plus lent que le plus rapide dans tous les environnements testés à l'exception de Opera, où il prend environ une fois et demie plus de temps. C'est lent car le moteur doit comparer la valeur deux fois pour chaque cas. Étonnamment, il faut Chrome près de 40 fois plus de temps que l'opération la plus rapide de Chrome, alors que MSIE ne prend que 6 fois plus de temps. Mais la différence de temps réelle n’était que de 74ms en faveur de MSIE à 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;
}

plage de commutation2

C'est une variante de switch-range mais avec une seule comparaison par cas et donc plus rapide, mais toujours très lente sauf dans Opera. L'ordre de l'instruction case est important car le moteur testera chaque cas dans l'ordre du code source ECMAScript262: 5 12.11

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

commutateur-tableau-indirect

Dans cette variante, les plages sont stockées dans un tableau. Ceci est lent dans tous les environnements testés et très lent dans 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;
}

tableau-linéaire-recherche

C'est une combinaison d'une recherche linéaire de valeurs dans un tableau et de l'instruction switch avec des valeurs fixes. La raison pour laquelle on peut vouloir utiliser ceci est lorsque les valeurs ne sont pas connues jusqu'au moment de l'exécution. Il est lent dans tous les environnements testés et prend presque 10 fois plus de temps dans 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;
}

tableau-commutateur-binaire

Ceci est une variante de array-linear-switch mais avec une recherche binaire. Malheureusement, il est plus lent que la recherche linéaire. Je ne sais pas si c'est ma mise en œuvre ou si la recherche linéaire est plus optimisée. Il se pourrait également que l’espace clavier soit trop petit.

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

Conclusion

Si les performances sont importantes, utilisez les instructions if- ou switch avec des valeurs immédiates.

643
some

Une alternative:

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

Démo: http://jsfiddle.net/UWYzr/

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

Ne fonctionne que si vous avez des pas réguliers ...

EDIT: comme cette solution ne cesse de recevoir des votes, je dois vous dire que la solution de mofolo est un meilleur moyen

20
IcanDivideBy0

Vous pouvez créer un objet personnalisé avec les critères et la fonction correspondant aux critères

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

Définissez des fonctions pour ce que vous voulez faire dans ces cas (définissez fonction1, fonction2, etc.)

Et "évaluer" les règles

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

Note

Je déteste utiliser 30 si déclarations

Plusieurs fois, si les déclarations sont plus faciles à lire et à maintenir. Je recommanderais ce qui précède uniquement lorsque vous avez beaucoup de conditions et une possibilité de beaucoup de croissance à l'avenir.

Mise à jour
Comme @Brad l'a souligné dans les commentaires, si les conditions sont mutuellement exclusives (une seule d'entre elles peut être vraie à la fois), il suffit de vérifier la limite supérieure:

if(scrollLeft < oneRule.upperLimit)

a fourni que les conditions sont définies par ordre croissant (la plus basse en premier lieu, 0 to 1000, puis 1000 to 2000 par exemple)

6
Nivas

Que faites-vous exactement dans //do stuff?

Vous pourrez peut-être faire quelque chose comme:

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

Non testé et incertain si cela fonctionnera, mais pourquoi ne pas faire quelques if statements avant, pour définir des variables pour le 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
Jason Gennaro

C'est une autre option:

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

Dans mon cas (codage couleur d'un pourcentage, rien de critique pour la performance), j'ai rapidement écrit ceci:

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
grebenyuksv

Mise à jour de la réponse acceptée (ne peut pas encore commenter). À compter du 12/12/16 avec la démo jsfiddle en chrome, switch-immediate est la solution la plus rapide.

Résultats: Résolution temporelle: 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

Fini

 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
1
jeffhale

Je déteste utiliser 30 si déclarations

J'ai eu la même situation ces derniers temps, c'est comme ça que j'ai résolu le problème:

avant:

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

après:

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

Et si vous définissez "1, 2, 3, 4, 5", alors cela peut être encore plus simple:

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