大于/小于的 switch 语句
Posted
技术标签:
【中文标题】大于/小于的 switch 语句【英文标题】:Switch statement for greater-than/less-than 【发布时间】:2011-10-03 16:56:33 【问题描述】:所以我想使用这样的 switch 语句:
switch (scrollLeft)
case (<1000):
//do stuff
break;
case (>1000 && <2000):
//do stuff
break;
现在我知道这些语句 (<1000
) 或 (>1000 && <2000
) 中的任何一个都不起作用(显然,出于不同的原因)。我要问的是最有效的方法。我讨厌使用 30 个 if
语句,所以我宁愿使用 switch 语法。有什么我可以做的吗?
【问题讨论】:
您的步数是否规律?我的意思是,如果你将scrollLeft除以1000,你可以切换1、2、3... 也许您可以制作一个排序数组,将条件范围映射到相应的操作,并对其应用二进制搜索。或者如果您的条件足够规则,您可以直接调用your_mapper_object[scrollLeft / SOME_CONST]
,假设your_mapper_object
类似于1: some_func, 2: another_func, ...
。在这种情况下,您还可以使用 switch。
【参考方案1】:
你到底在//do stuff
做什么?
您可以执行以下操作:
(scrollLeft < 1000) ? //do stuff
: (scrollLeft > 1000 && scrollLeft < 2000) ? //do stuff
: (scrollLeft > 2000) ? //do stuff
: //etc.
【讨论】:
【参考方案2】:您可以创建具有条件的自定义对象以及与条件对应的函数
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 在 cmets 中指出的那样,如果条件是互斥的(一次只能有一个为真),检查上限就足够了:
if(scrollLeft < oneRule.upperLimit)
假设条件是按升序定义的(例如,首先是最低的,0 to 1000
,然后是1000 to 2000
)
【讨论】:
action=function1
-- 这些不应该是冒号吗? ;-) -- 您也可以将其重构为只有一个上限,因为由于消除过程,您不能属于两组 - 除非这是您的意图(可能有多个操作)。
@Brad,不,这不是我的意图,你是对的,上限应该足够了。将其添加为更新...
我觉得这个简洁干净+1【参考方案3】:
switch (Math.floor(scrollLeft/1000))
case 0: // (<1000)
//do stuff
break;
case 1: // (>=1000 && <2000)
//do stuff;
break;
仅当您有常规步骤时才有效...
编辑:由于此解决方案不断获得支持,我必须建议 mofolo's solution 更好
【讨论】:
顺便说一下我用了Math.round(scrollLeft/1000)
。
@Switz - 请记住,999 = 1000,而不仅仅是 >1000。
mofolo 解决方案的唯一问题是它在 Chrome 中的速度比 IcanDivideBy0 的慢大约 30 倍。请在下方查看我的answer。【参考方案4】:
未经测试并且不确定这是否会起作用,但为什么不在之前做一些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;
【讨论】:
【参考方案5】:另一种选择:
var scrollleft = 1000;
switch (true)
case (scrollleft > 1000):
alert('gt');
break;
case (scrollleft <= 1000):
alert('lt');
break;
演示:http://jsfiddle.net/UWYzr/
【讨论】:
这是一个更有价值的解决方案。 +1 这不是和if(...) else if(...)
一样吗?这确实避免了if
,但听起来对我来说不是一个很好的替代品。
虽然代码很优雅,但会损害性能。在 Chrome 中它比使用if
-statements 慢了近 30 倍。见我的answer here
但是,当正在处理的数据不大并且可能仅应用一个函数(例如验证单个用户输入)时,这种性能损失可以忽略不计,那么在这种情况下选择可读性而不是性能。跨度>
这正是我想要的。谢谢!【参考方案6】:
这是另一种选择:
switch (true)
case (value > 100):
//do stuff
break;
case (value <= 100)&&(value > 75):
//do stuff
break;
case (value < 50):
//do stuff
break;
【讨论】:
【参考方案7】:当我查看其他答案中的解决方案时,我看到了一些我知道对性能不利的事情。我打算将它们放在评论中,但我认为最好对其进行基准测试并分享结果。你可以test it yourself。下面是我在每个浏览器中最快运行后归一化的结果(ymmv)。
这是 2021 年 5 月 5 日的结果
Test | Chrome | Firefox | Opera | Edge | Brave | Node |
---|---|---|---|---|---|---|
1.0 time | 15 ms | 14 ms | 17 ms | 17 ms | 16 ms | 14 ms |
if-immediate | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 |
if-indirect | 2.20 | 1.21 | 2.06 | 2.18 | 2.19 | 1.93 |
switch-immediate | 2.07 | 1.43 | 1.71 | 1.71 | 2.19 | 1.93 |
switch-range | 3.60 | 2.00 | 2.47 | 2.65 | 2.88 | 2.86 |
switch-range2 | 2.07 | 1.36 | 1.82 | 1.71 | 1.94 | 1.79 |
switch-indirect-array | 2.93 | 1.57 | 2.53 | 2.47 | 2.75 | 2.50 |
array-linear-switch | 2.73 | 3.29 | 2.12 | 2.12 | 2.38 | 2.50 |
array-binary-switch | 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.123 em>、Edge 90.0.818.62、Brave 1.24.85、Node 16.1.0(在 WSL 下运行)
Apple 不会更新 Windows 版 Safari,所以它仍然是 5.1.7。我在这次测试中将其更改为 Brave。
这是 2012 年 9 月 4 日的结果,用于历史比较:
Test | Chrome | Firefox | Opera | MSIE | Safari | Node |
---|---|---|---|---|---|---|
1.0 time | 37 ms | 73 ms | 68 ms | 184 ms | 73 ms | 21 ms |
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 |
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 毫秒。
如果立即
这是所有测试环境中最快的方法,除了 ... drumroll MSIE! (惊喜,惊喜)。
这是推荐的实现方式。
if (val < 1000) /*do something */ else
if (val < 2000) /*do something */ else
...
if (val < 30000) /*do something */ else
如果间接
这是switch-indirect-array
的变体,但使用if
-statements 代替,并且在所有测试引擎中都更快。
2021 年比最快的测试慢 20-120%(2012 年:0-280%)。与 2012 年 (1.2) 相比,Chrome 在 2021 年 (2.20) 花费的时间更长
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
立即切换
当您可以进行计算以获取索引时,此方法有效。
在 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;
开关范围
这很慢,因为引擎必须为每种情况比较两次值。
在 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;
开关范围2
这是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;
切换间接数组
在这个变体中,范围存储在一个数组中。
在 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-linear-switch
的变体,但具有二进制搜索。
不幸的是,它比线性搜索慢。我不知道这是我的实现还是线性搜索更优化。也可能是键空间太小。
在 2021 年,这比 2012 年慢了 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
-statements 或switch
,以及立即值。
【讨论】:
很难看到有如此详细和整洁结构的答案。大+1 Big +1 解释这个问题的性能方面! 这就是为什么 *** 是最好的答案之一。这是一个“永恒”的答案,干得好,感谢 jsfiddle! grt 信息和解释 真希望我能+2,这么详细的答案!【参考方案8】:更新接受的答案(尚无法评论)。截至 16 年 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
【讨论】:
这真的取决于 - 15ms “if-immediate” 15ms “if-indirect” 15ms “switch-immediate” 37ms “switch-range” 28ms “switch-range2” 35ms “switch-indirect-array” 29ms "array-linear-switch" 62ms "array-binary-switch" 完成 1.00 ( 15ms) if-immediate 1.00 ( 15ms) if-indirect 1.00 ( 15ms) switch-immediate 2.47 ( 37ms) switch-range 1.87 ( 28ms) switch -range2 2.33 (35ms) switch-indirect-array 1.93 (29ms) array-linear-switch 4.13 (62ms) array-binary-switch chrome 版本 48.0.2564.109 (64-bit) mac os x 10.11.3 ATM Safari 9.X on Mac OS x 和 Safari ios 9.3,"if-immediate" 是明显的赢家 1 毫秒的差异太小了。它比每次测试运行的变化更大。重点是:使用有意义的编码风格,不要尝试微优化。【参考方案9】:在我的例子中(对百分比进行颜色编码,对性能没有任何要求),我很快写了这个:
function findColor(progress)
const thresholds = [30, 60];
const colors = ["#90B451", "#F9A92F", "#90B451"];
return colors.find((col, index) =>
return index >= thresholds.length || progress < thresholds[index];
);
【讨论】:
【参考方案10】:我讨厌使用 30 个 if 语句
我最近也遇到了同样的情况,我就是这样解决的:
之前:
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;
之后:
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++);
【讨论】:
以上是关于大于/小于的 switch 语句的主要内容,如果未能解决你的问题,请参考以下文章