Javascript 大于/小于的 switch 语句
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6665997/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Switch statement for greater-than/less-than
提问by switz
so I want to use a switch statement like this:
所以我想使用这样的 switch 语句:
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?
现在我知道这些语句 ( <1000
) 或 ( >1000 && <2000
) 中的任何一个都不起作用(显然出于不同的原因)。我要问的是最有效的方法来做到这一点。我讨厌使用 30 条if
语句,所以我宁愿使用 switch 语法。有什么我可以做的吗?
回答by some
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 (multiply the 1.0 time with the normalized value to get the absolute time in ms).
当我查看其他答案中的解决方案时,我看到了一些我知道对性能不利的事情。我打算将它们放在评论中,但我认为最好对其进行基准测试并分享结果。你可以自己测试一下。下面是我在每个浏览器中最快操作后归一化的结果 (ymmv)(将 1.0 时间乘以归一化值以获得以毫秒为单位的绝对时间)。
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 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. Nodewas run on a Linux 64bit box because the timer resolution on Node.js for Windows was 10ms instead of 1ms.
测试在 Windows 7 32 位上执行的以下版本:Chrome 21.0.1180.89m、Firefox 15.0、Opera 12.02、MSIE 9.0.8112、Safari 5.1.7。Node在 Linux 64 位机器上运行,因为 Node.js for Windows 上的计时器分辨率是 10 毫秒而不是 1 毫秒。
if-immediate
如果立即
This is the fastest in all tested environments, except in ... drumrollMSIE! (surprise, surprise). This is the recommended way to implement it.
这是所有测试环境中最快的,除了...鼓声MSIE!(惊喜,惊喜)。这是实现它的推荐方法。
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 performs much faster than switch-indirect-array
in almost all tested environments.
这是switch-indirect-array
但使用if
-statements的变体,并且比switch-indirect-array
几乎所有测试环境的执行速度都快得多。
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 is pretty fast in all tested environments, and actually the fastest in MSIE. It works when you can do a calculation to get an index.
这在所有测试环境中都非常快,实际上在 MSIE 中是最快的。当您可以进行计算以获取索引时,它会起作用。
switch (Math.floor(val/1000)) {
case 0: /* do something */ break;
case 1: /* do something */ break;
...
case 29: /* do something */ break;
}
switch-range
开关量程
This is about 6 to 40 times slower than the fastest in all tested environments except for Opera where it takes about one and a half times as long. It is slow because the engine has to compare the value twice for each case. Surprisingly it takes Chrome almost 40 times longer to complete this compared to the fastest operation in Chrome, while MSIE only takes 6 times as long. But the actual time difference was only 74ms in favor to MSIE at 1337ms(!).
这比所有测试环境中最快的速度慢约 6 到 40 倍,除了 Opera 需要大约一倍半的时间。它很慢,因为引擎必须为每种情况比较两次值。令人惊讶的是,与 Chrome 中最快的操作相比,Chrome 完成此操作所需的时间几乎是 Chrome 的 40 倍,而 MSIE 只需要 6 倍的时间。但实际时差只有 74 毫秒,而 MSIE 为 1337 毫秒(!)。
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
开关范围2
This is a variant of switch-range
but with only one compare per case and therefore faster, but still very slow except in Opera. The order of the case statement is important since the engine will test each case in source code order ECMAScript262:5 12.11
这是一种变体,switch-range
但每个案例只有一个比较,因此速度更快,但除 Opera 外仍然非常慢。case 语句的顺序很重要,因为引擎将按照源代码顺序测试每个 case 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
开关间接阵列
In this variant the ranges is stored in an array. This is slow in all tested environments and very slow in Chrome.
在这个变体中,范围存储在一个数组中。这在所有测试环境中都很慢,在 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
数组线性搜索
This is a combination of a linear search of values in an array, and the switch statement with fixed values. The reason one might want to use this is when the values isn't known until runtime. It is slow in every tested environment, and takes almost 10 times as long in MSIE.
这是数组中值的线性搜索和具有固定值的 switch 语句的组合。人们可能想要使用它的原因是直到运行时才知道这些值。它在每个测试环境中都很慢,在 MSIE 中几乎是它的 10 倍。
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.
这是一种变体,array-linear-switch
但具有二分搜索。不幸的是,它比线性搜索慢。我不知道是我的实现还是线性搜索更优化了。也可能是键空间太小。
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.
如果性能很重要,请使用if
-statements 或switch
立即值。
回答by labue
An alternative:
替代:
var scrollleft = 1000;
switch (true)
{
case (scrollleft > 1000):
alert('gt');
break;
case (scrollleft <= 1000):
alert('lt');
break;
}
回答by IcanDivideBy0
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 solutionis a way better
编辑:由于此解决方案不断获得赞成票,因此我必须建议mofolo 的解决方案更好
回答by Nivas
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)
在这些情况下为您想要执行的操作定义函数(定义函数 1、函数 2 等)
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
我讨厌使用 30 个 if 语句
Many times if statements are easier to read and maintain. I would recommend the above only when you have a lot of conditions anda possibility of lot ofgrowth in the future.
很多时候 if 语句更容易阅读和维护。只有当您有很多条件并且将来有很多增长的可能性时,我才会推荐上述内容。
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:
更新
正如@Brad 在评论中指出的那样,如果条件是互斥的(一次只能有一个为真),检查上限就足够了:
if(scrollLeft < oneRule.upperLimit)
providedthat the conditions are defined in ascending order (first the lowest one, 0 to 1000
, and then 1000 to 2000
for example)
如果条件是按升序定义的(例如0 to 1000
,首先是最低的,然后1000 to 2000
是)
回答by Jason Gennaro
Untested and unsure if this will work, but why not do a few if statements
before, to set variables for the switch statement
.
未经测试且不确定这是否有效,但为什么不先做一些if statements
,为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;
}
回答by Igor
What exactly are you doing in //do stuff
?
你到底在做什么//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.
回答by Pablo Claus
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;
}
回答by jeffhale
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.
更新已接受的答案(尚不能评论)。截至 2016 年 1 月 12 日,在 chrome 中使用演示 jsfiddle 时,立即切换是最快的解决方案。
Results: Time resolution: 1.33
结果:时间分辨率: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
回答by grebenyuksv
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];
});
}
回答by Martin
I hate using 30 if statements
我讨厌使用 30 个 if 语句
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:
如果你设置 "1, 2, 3, 4, 5" 那么它可以更简单:
var scales = [4, 6, 9, 12, 18];
scales.forEach(function(el){if(wind_speed >= el) scale++});