大于/小于的 switch 语句
所以我想使用这样的 switch 语句:
so I want to use a switch statement like this:
switch (scrollLeft) {
case (<1000):
//do stuff
break;
case (>1000 && <2000):
//do stuff
break;
}
现在我知道这些语句 (<1000
) 或 (>1000 && <2000
) 都不起作用(对于不同的原因,很明显).我要问的是最有效的方法.我讨厌使用 30 个 if
语句,所以我宁愿使用 switch 语法.有什么我可以做的吗?
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?
推荐答案
当我查看其他答案中的解决方案时,我看到了一些我知道对性能不利的事情.我打算将它们放在评论中,但我认为最好对其进行基准测试并分享结果.你可以自己测试一下.下面是我在每个浏览器中最快运行后归一化的结果(ymmv).
When I looked at the solutions in the other answers I saw some things that I know are bad for performance. I was going to put them in a comment but I thought it was better to benchmark it and share the results. You can test it yourself. Below are my results (ymmv) normalized after the fastest operation in each browser.
这是 2021 年 5 月 5 日的结果
Here is the results from 2021-MAY-05
测试 | Chrome | 火狐 | 歌剧 | 边缘 | 勇敢 | 节点 |
---|---|---|---|---|---|---|
1.0倍 | 15 毫秒 | 14 毫秒 | 17 毫秒 | 17 毫秒 | 16 毫秒 | 14 毫秒 |
如果-立即 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
如果间接 | 2.20 | 1.21 | 2.06 | 2.18 | 2.19 | 1.93 |
立即切换 | 2.07 | 1.43 | 1.71 | 1.71 | 2.19 | 1.93 |
开关范围 | 3.60 | 2.00 | 2.47 | 2.65 | 2.88 | 2.86 |
开关范围2 | 2.07 | 1.36 | 1.82 | 1.71 | 1.94 | 1.79 |
切换间接数组 | 2.93 | 1.57 | 2.53 | 2.47 | 2.75 | 2.50 |
阵列线性开关 | 2.73 | 3.29 | 2.12 | 2.12 | 2.38 | 2.50 |
数组二进制开关 | 5.80 | 6.07 | 5.24 | 5.24 | 5.44 | 5.37 |
2021 年的测试在 Windows 10 64bit 上执行,以下版本:Chrome 90.0.4430.212、Firefox 89.0b13、Opera 76.0.4017.123em>、Edge 90.0.818.62、Brave 1.24.85、Node 16.1.0(在 WSL 下运行)
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 不会更新 Windows 版 Safari,所以它仍然是 5.1.7.我在这次测试中将其更改为 Brave.
Apple doesn't update Safari for Windows, so it is still 5.1.7. I changed it to Brave in this test.
这是 2012 年 9 月 4 日的结果,用于历史比较:
Here is the results from 2012-September-04, for historical comparison:
测试 | Chrome | 火狐 | 歌剧 | MSIE | Safari | 节点 |
---|---|---|---|---|---|---|
1.0倍 | 37 毫秒 | 73 毫秒 | 68 毫秒 | 184 毫秒 | 73 毫秒 | 21 毫秒 |
如果-立即 | 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 |
2012 年在 Windows 7 32bit 上进行的测试,使用以下版本:Chrome 21.0.1180.89m、Firefox 15.0、Opera 12.02,MSIE 9.0.8112,Safari 5.1.7.Node 是在 Linux 64 位机器上运行的,因为 Windows 的 Node 上的计时器分辨率是 10 毫秒而不是 1 毫秒.
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.
这是所有测试环境中最快的方法,除了 ... drumroll MSIE!(惊喜,惊喜).
This is the fastest method in all tested environments, except in ... drumroll MSIE! (surprise, surprise).
这是推荐的实现方式.
if (val < 1000) { /*do something */ } else
if (val < 2000) { /*do something */ } else
...
if (val < 30000) { /*do something */ } else
如果间接
这是 switch-indirect-array
的变体,但使用 if
-statements 代替,并且在所有测试引擎中都更快.
if-indirect
This is a variant of switch-indirect-array
but with if
-statements instead and is faster in all tested engines.
2021 年比最快的测试慢 20-120%(2012 年:0-280%).与 2012 年 (1.2) 相比,Chrome 在 2021 年 (2.20) 花费的时间更长
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.
在 2021 年,它比 if-immediate
慢 40-120%(2012 年:0-180%),但实际上是最快的 MSIE 除外.
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.
在 2021 年,它比最快的测试慢 1-2.6(2012 年:1.6-38)倍.Chrome 从 38 到 3.6 的改进最大,但仍然是测试最慢的引擎.
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;
}
开关范围2
这是 switch-range
的变体,但每个案例只有一次比较,因此速度更快.case 语句的顺序很重要,因为引擎将按源代码顺序测试每个案例 ECMAScript 2020 13.12.9
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
2021 年比最快的测试慢 36-107%,但在 2012 年慢了 1-31 倍.在这次测试中表现最差的仍然是 Chrome,但已经从 32 倍提升到了 2 倍.
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.
在 2021 年,它比最快的测试慢了 57-193%(2012 年:3-35 倍).所有测试引擎的性能都有所提高,虽然 Chrome 仍然是最慢的,但它已从 35 提高到 2.93.
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.
在 2021 年,它比最快的测试慢了 57-193%(2012 年:3-35 倍).所有测试引擎的性能都有所提高,虽然 Chrome 仍然是最慢的,但它已从 35 提高到 2.93.
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-linear-switch
的变体,但带有二进制搜索.不幸的是,它比线性搜索慢.我不知道这是我的实现还是线性搜索更优化.也可能是键空间太小.
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.
在 2021 年,这比 2012 年慢了 4-5 倍(2012 年:4-16 倍).请勿使用.
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;
}
结论
如果性能很重要,请使用 if
-statements 或 switch
,并带有立即值.
Conclusion
If performance is important, use if
-statements or switch
, with immediate values.
相关文章