大于/小于的 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;

现在我知道这些语句 (&lt;1000) 或 (&gt;1000 &amp;&amp; &lt;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.212Firefox 89.0b13Opera 76.0.4017.123 em>、Edge 90.0.818.62Brave 1.24.85Node 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.89mFirefox 15.0Opera 12.02MSIE 9.0.8112Safari 5.1.7Node 是在 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 语句的主要内容,如果未能解决你的问题,请参考以下文章

IF..else与switch语句记录

采用switch语句设计一个程序,对给定的学生成绩score评判其等级这个程序怎么编啊??

如何配置ibatis语句带小于号的

如何配置ibatis语句带小于号的?

如何在 switch 语句中使用大于或等于

用SQL语句查询出年龄大于19且小于23的男学生信息