大于/小于的 switch 语句

发布于 2024-11-19 18:54:08 字数 364 浏览 1 评论 0原文

所以我想使用这样的 switch 语句:

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

现在我知道这些语句 (<1000) 或 (>1000 && <2000 )不起作用(显然出于不同的原因)。我要问的是做到这一点的最有效的方法。我讨厌使用 30 个 if 语句,所以我宁愿使用 switch 语法。有什么我可以做的吗?

so I want to use a switch statement like this:

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

Now I know that either of those statements (<1000) or (>1000 && <2000) won't work (for different reasons, obviously). What I'm asking is the most efficient way to do just that. I hate using 30 if statements, so I'd rather use the switch syntax. Is there anything that I can do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

梓梦 2024-11-26 18:54:08

查看其他答案中的解决方案,我发现根据过去的经验,我发现一些对性能不利的事情。

我已经在不同的浏览器中测试了多种解决方案,下面是按每个浏览器中最快的操作标准化的结果 (ymmv)。

的结果

以下是 2021 年 5 月 5 日测试ChromeFirefoxOperaEdgeBraveNode
1.0 时间15 ms14 ms17 ms17 ms16 ms14 ms
if-immediate1.001.001.001.001.001.00
if-indirect2.201.212.062.182.191.93
开关立即2.071.431.711.712.191.93
开关范围3.602.002.472.652.88 2.86开关
范围2 2.071.361.821.711.941.79
开关间接数组2.931.572.532.472.752.50
array-线性-switch2.733.292.122.122.382.50
array-binary-switch5.806.075.245.245.445.37

2021 年在 Windows 10 上执行的测试64 位,具有以下版本:Chrome 90.0.4430.212Firefox 89.0b13Opera 76.0.4017.123Edge 90.0.818.62 em>、Brave 1.24.85Node 16.1.0(在 WSL 下运行)

Apple 不会更新 Windows 版 Safari,因此它仍然是 5.1.7。我在这次测试中将其更改为Brave。

以下是 2012 年 9 月 4 日的结果,用于历史比较:

TestChromeFirefoxOperaMSIESafariNode
1.0 time37 ms73 ms68 ms184 ms73 ms21 ms
if-immediate1.01.01.02.61.01.0
if-indirect1.21.83.33.82.61.0
开关立即2.01.12.01.02.81.3
开关范围38.110.62.67.320.910.4
开关范围231.98.32.04.59.56.9
开关间接数组35.29.64.25.510.78.6
array-线性-switch3.64.14.510.04.72.7
array-binary-switch7.86.79.516.015.04.9

2012 年的测试在 Windows 7 32 位上执行,版本如下:Chrome 21.0.1180.89m, Firefox 15.0Opera 12.02MSIE 9.0.8112Safari 5.1.7Node 在 Linux 64 位机器上运行,因为 Windows 版 Node 上的计时器分辨率是 10 毫秒,而不是 1 毫秒。

if-immediate

这是所有测试环境中最快的方法,除了... drumroll MSIE! (惊讶,惊讶)。

这是推荐的实现方式。

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

if-indirect

这是 switch-indirect-array 的变体,但用 if 语句代替,在所有测试的发动机中速度更快。

2021 年,它比最快的测试慢了 20-120%(2012 年:0-280%)。 Chrome 在 2021 年 (2.20) 比 2012 年 (1.2) 花费的时间更长

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

当您可以进行计算来获取索引时,此方法有效。

2021 年,它比 if-immediate 慢 40-120%(2012 年:0-180%),但 MSIE 除外,它实际上是最快的。

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

switch-range

它很慢,因为引擎必须为每种情况比较两次值。

2021 年,它比最快的测试慢了 1-2.6 倍(2012 年:1.6-38)倍。
Chrome 取得了最大的改进,从 38 到 3.6,但仍然是经过测试的最慢的引擎。

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

这是 switch-range 的一种变体,但每种情况只有一次比较,因此速度更快。
case 语句的顺序很重要,因为引擎将按源代码顺序测试每个 case ECMAScript 2020 13.12.9

在 2021 年,它比最快的测试慢了 36-107%,但在 2012 年,它是慢1-31倍。在这次测试中表现最差的仍然是 Chrome,但它已经从 32 倍提高到了 2 倍。

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

switch-indirect-array

在此变体中,范围存储在数组中。

2021 年,它比最快的测试慢了 57-193%(2012 年:3-35 倍)。
所有测试引擎的性能都有所提高,虽然 Chrome 仍然是最慢的,但它已从 35 提高到 2.93。

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

数组线性搜索

在此变体中,范围存储在数组中。

2021 年,它比最快的测试慢了 57-193%(2012 年:3-35 倍)。
所有测试引擎的性能都有所提高,虽然 Chrome 仍然是最慢的,但它已从 35 提高到 2.93。

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

这是 array-linear-switch 的变体,但具有二分搜索。
不幸的是它比线性搜索慢。我不知道这是我的实现还是线性搜索更优化。也可能是密钥空间太小。

2021 年,这一速度慢了 4-5 倍(2012 年:4-16)倍。 请勿使用

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

Looking at the solutions in the other answers, I saw a few things that I know from past experience are bad for performance.

I've tested several solutions, in different browsers, and below are my results (ymmv) normalized by the fastest operation in each browser.

Here is the results from 2021-MAY-05

TestChromeFirefoxOperaEdgeBraveNode
1.0 time15 ms14 ms17 ms17 ms16 ms14 ms
if-immediate1.001.001.001.001.001.00
if-indirect2.201.212.062.182.191.93
switch-immediate2.071.431.711.712.191.93
switch-range3.602.002.472.652.882.86
switch-range22.071.361.821.711.941.79
switch-indirect-array2.931.572.532.472.752.50
array-linear-switch2.733.292.122.122.382.50
array-binary-switch5.806.075.245.245.445.37

The tests in 2021 where performed on Windows 10 64bit with the following versions: Chrome 90.0.4430.212, Firefox 89.0b13, Opera 76.0.4017.123, Edge 90.0.818.62, Brave 1.24.85, and Node 16.1.0 (was run under WSL)

Apple doesn't update Safari for Windows, so it is still 5.1.7. I changed it to Brave in this test.

Here is the results from 2012-September-04, for historical comparison:

TestChromeFirefoxOperaMSIESafariNode
1.0 time37 ms73 ms68 ms184 ms73 ms21 ms
if-immediate1.01.01.02.61.01.0
if-indirect1.21.83.33.82.61.0
switch-immediate2.01.12.01.02.81.3
switch-range38.110.62.67.320.910.4
switch-range231.98.32.04.59.56.9
switch-indirect-array35.29.64.25.510.78.6
array-linear-switch3.64.14.510.04.72.7
array-binary-switch7.86.79.516.015.04.9

The tests in 2012 where performed on Windows 7 32bit with the folowing versions: Chrome 21.0.1180.89m, Firefox 15.0, Opera 12.02, MSIE 9.0.8112, Safari 5.1.7. Node was run on a Linux 64bit box because the timer resolution on Node for Windows was 10ms instead of 1ms.

if-immediate

This is the fastest method in all tested environments, except in ... drumroll MSIE! (surprise, surprise).

This is the recommended way to implement it.

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

if-indirect

This is a variant of switch-indirect-array but with if-statements instead and is faster in all tested engines.

In 2021 it was 20-120% (2012: 0-280%) slower than the fastest test. Chrome takes longer time in 2021 (2.20) than in 2012 (1.2)

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

This works when you can do a calculation to get an index.

In 2021 it was 40-120% (2012: 0-180%) slower than if-immediate, except in MSIE where it actually was the fastest.

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

switch-range

It is slow because the engine has to compare the value twice for each case.

In 2021 it was 1-2.6 (2012: 1.6-38) times slower than the fastest test.
Chrome has made the biggest improvement from 38 to 3.6, but is still the slowest tested engine.

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

This is a variant of switch-range but with only one compare per case and therefore faster.
The order of the case statement is important since the engine will test each case in source code order ECMAScript 2020 13.12.9

In 2021 it was 36-107% slower than the fastest test, but in 2012 it was 1-31 times slower. It is still Chrome who has the worst performance on this test, but it has improved from 32 to 2 times.

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

switch-indirect-array

In this variant the ranges is stored in an array.

In 2021 it was 57-193% (2012: 3-35 times) slower than the fastest test.
The perormance has improved in all tested engines, and while Chrome is still the slowest, it has improved from 35 to 2.93.

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

In this variant the ranges is stored in an array.

In 2021 it was 57-193% (2012: 3-35 times) slower than the fastest test.
The perormance has improved in all tested engines, and while Chrome is still the slowest, it has improved from 35 to 2.93.

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

This is a variant of array-linear-switch but with a binary search.
Unfortunately it is slower than the linear search. I don't know if it is my implementation or if the linear search is more optimized. It could also be that the keyspace is to small.

In 2021 this was 4-5 (2012: 4-16) times slower. Do not use.

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

If performance is important, use if-statements or switch, with immediate values.

牛↙奶布丁 2024-11-26 18:54:08

另一种选择:

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

演示:http://jsfiddle.net/UWYzr/

An alternative:

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

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

把昨日还给我 2024-11-26 18:54:08
switch (Math.floor(scrollLeft/1000)) {
  case 0: // (<1000)
   //do stuff
   break;
  case 1: // (>=1000 && <2000)
   //do stuff;
   break;
}

仅当您有常规步骤时才有效...

编辑:由于此解决方案不断获得支持,我必须建议 mofolo 的解决方案 更好

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

Only works if you have regular steps...

EDIT: since this solution keeps getting upvotes, I must advice that mofolo's solution is a way better

眉黛浅 2024-11-26 18:54:08

您可以使用条件和与条件对应的函数创建自定义对象

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

在这些情况下定义您想要执行的操作的函数(定义函数 1、函数 2 等)

并“评估”规则

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 语句更容易阅读和维护。
仅当您有很多条件并且未来有大量增长的可能性时,我才会推荐上述内容。

更新
正如 @Brad 在评论中指出的,如果条件是互斥的(一次只能其中一个为真),检查上限应该足够了:

if(scrollLeft < oneRule.upperLimit)

假设条件是在升序(例如,首先是最低的,0 到 1000,然后是 1000 到 2000

You can create a custom object with the criteria and the function corresponding to the criteria

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

Define functions for what you want to do in these cases (define function1, function2 etc)

And "evaluate" the rules

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

I hate using 30 if statements

Many times if statements are easier to read and maintain.
I would recommend the above only when you have a lot of conditions and a possibility of lot of growth in the future.

Update
As @Brad pointed out in the comments, if the conditions are mutually exclusive (only one of them can be true at a time), checking the upper limit should be sufficient:

if(scrollLeft < oneRule.upperLimit)

provided that the conditions are defined in ascending order (first the lowest one, 0 to 1000, and then 1000 to 2000 for example)

甜柠檬 2024-11-26 18:54:08

你到底在 //do stuff 中做什么?

您也许可以执行以下操作:

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

What exactly are you doing in //do stuff?

You may be able to do something like:

(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc. 
过度放纵 2024-11-26 18:54:08

这是另一种选择:

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

This is another option:

     switch (true) {
         case (value > 100):
             //do stuff
             break;
         case (value <= 100)&&(value > 75):
             //do stuff
             break;
         case (value < 50):
            //do stuff
             break;
     }
纸短情长 2024-11-26 18:54:08

未经测试且不确定这是否有效,但为什么不在之前执行一些 if 语句,为 switch 语句 设置变量。

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

Untested and unsure if this will work, but why not do a few if statements before, to set variables for the 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;
}
银河中√捞星星 2024-11-26 18:54:08

更新已接受的答案(尚无法发表评论)。截至 2016 年 1 月 12 日,在 chrome 中使用演示 jsfiddle,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

Updating the accepted answer (can't comment yet). As of 1/12/16 using the demo jsfiddle in chrome, switch-immediate is the fastest solution.

Results:
Time resolution: 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

Finished

 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
滿滿的愛 2024-11-26 18:54:08

就我而言(对百分比进行颜色编码,没有对性能至关重要),我很快写道:

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

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

In my case (color-coding a percentage, nothing performance-critical), I quickly wrote this:

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

    return colors.find((col, index) => {
        return index >= thresholds.length || progress < thresholds[index];
    });
}
花开浅夏 2024-11-26 18:54:08

我讨厌使用 30 个 if 语句

我最近遇到了同样的情况,这就是我解决它的方法:

before:

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

after:

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

I hate using 30 if statements

I had the same situation lately, that's how I solved it:

before:

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

after:

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

And if you set "1, 2, 3, 4, 5" then it can be even simpler:

var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文