使用字符串选项优化if-else / switch-case
这段代码会带来什么修改? 在最后几行中,我应该使用更多的if-else结构,而不是“ if-if-if”
if (action.equals("opt1")) { //something } else { if (action.equals("opt2")) { //something } else { if ((action.equals("opt3")) || (action.equals("opt4"))) { //something } if (action.equals("opt5")) { //something } if (action.equals("opt6")) { //something } } }
稍后编辑:这是Java。 我认为switch-case结构不适用于Strings。
后来编辑2:
交换机使用byte,short,char和int原始数据类型。 它还适用于枚举类型(在类和inheritance中讨论)和一些“包装”某些基本类型的特殊类:Character,Byte,Short和Integer(在简单数据对象中讨论)。
即使你不使用switch语句,是的,如果要避免无用的比较,请使用else:如果第一个if被采用,你不希望在这里评估所有其他ifs,因为它们总是假的。 如果最后一个块是如此缩进以至于在没有滚动的情况下看不到它,你也不需要缩进,下面的代码是完全可读的:
if (action.equals("opt1")) { } else if (action.equals("opt2")) { } else if (action.equals("opt3")) { } else { }
使用字符串作为键类型的字典,并将*作为值类型委托。 – 从使用字符串中检索方法将需要O(1 +加载)。
在类的构造函数中填充字典。
- Java不支持委托,因此解决方法可能需要定义一些内部类 – 每种情况一个,并传递内部类的实例而不是方法作为值。
假设您的语言支持切换字符串,请使用switch语句。
switch(action) { case "opt6": // break; case "opt7": // ... ... ... }
在Java中有很多方法可以做到这一点,但这里有一个很好的方法。
enum Option { opt1, opt2, opt3, opt4, opt5, opt6 } ... switch (Option.valueOf(s)) { case opt1: // do opt1 break; case opt2: // do opt2 break; case opt3: case opt4: // do opt3 or opt4 break; ... }
请注意,如果参数不是枚举的其中一个成员的名称, valueOf(String)
将抛出IllegalArgumentException
。 在引擎盖下,valueOf的实现使用静态hashmap将其String参数映射到枚举值。
你可以使用开关。
switch (action) { case "opt3": case "opt4": doSomething; break; case "opt5": doSomething; break; default: doSomeWork; break; }
如果您指定语言可能会有所帮助……因为它看起来像C ++,您可以使用switch。
switch (action) { case "opt1": // something break; case "opt2": // something break; ... }
如果您想使用if语句,我认为如果您使用“else if”而不使用花括号,您可以稍微提高可读性和性能,如:
if (action.equals("opt1")) { //something } else if (action.equals("opt2")) { //something } else if ((action.equals("opt3")) || (action.equals("opt4"))) { //something } else if (action.equals("opt5")) { //something } else if (action.equals("opt6")) { //something }
我认为一些编译器可以优化else if
优于else { if
。 无论如何,我希望我能帮忙!
我会把它清理成一系列if / else语句:
if(action.equals("opt1")) { // something } else if (action.equals("opt2")) { // something } else if (action.equals("opt3")) { // something } etc...
这取决于你的语言,但它看起来像C,所以你可以尝试一个switch语句:
switch(action) { case "opt1": // something break; case "opt2": // something break; case "opt3": case "opt4": // something break; case "opt5": // something break; case "opt6": // something break; }
但是,有时switch语句不能提供足够的清晰度或灵活性(正如Victor在下面提到的那样,在某些语言中不适用于字符串)。 大多数编程语言都会有一种说“别的”的方式,而不是写作
if (condition1) { ... } else { if (condition2) { ... } else { if (condition3) { ... } else { // This can get very indented very fast } } }
…有一堆缩进,你可以写这样的东西:
if (condition1) { ... } else if (condition2) { ... } else if (condition3) { ... } else { ... }
在C / C ++中我相信C#, else if
。 在Python中,它是elif
。
建议使用switch语句的答案是要走的路。 switch语句比你现在拥有的if
和if...else
语句更容易阅读。
简单的比较很快,并且除了一种情况之外,所有代码都不会执行,因此您可以跳过“优化”并选择“可维护性”。
当然,假设action.equals()
方法做了一些微不足道的事情,比如==
。 如果action.equals()
很昂贵,那么你还有其他问题。
像这样的程序切换通常由多态性更好地处理 – 而不是由字符串表示的动作,表示具有可以专门化的’某事’方法的对象的动作。 如果您发现需要将字符串映射到该选项,请使用Map
。
如果你想坚持程序代码,真实代码中的选项都是“optX”:
if ( action.startsWith("opt") && action.length() == 4 ) { switch ( action.charAt(3) ) { case '1': something; break; case '2': something; break; case '3': something; break; ... } }
在解析器(破坏字符串是问题域的一部分)之类的东西中是可以的,并且应该很快,但不具有内聚性(对象action
和行为之间的连接基于其表示的部分而不是对象的任何内在因素)。
实际上,这取决于分支分析。 如果99%的决定都是“opt1”,那么这段代码就已经相当不错了。 如果99%的决定都是“opt6”,那么这段代码就是丑陋的。
如果您经常“opt6”并且很少“opt1”在第一次比较中输入“opt6”,并根据执行数据流中字符串的频率对以下比较进行排序。
如果你有很多选项并且频率相同,你可以对选项进行排序并将它们拆分成二进制树的forms,如下所示:
if (action < "opt20") { if( action < "opt10" ) { if( action == "opt4" ) {...} else if( action == "opt2" ) {...} else if( action == "opt1" ) {...} else if( action == "opt8" ) {...} } } else { if( action < "opt30 ) { } else { if( action == "opt38" ) {...} else if( action == "opt32" ) {...} } }
在此示例中,范围拆分将“opt38”和“opt4”所需的比较减少到3.因此,您可以在每个分支中获得log2(n)+1比较。 这对于选项的相同频率是最佳的。
不要二进制吐出到最后,最后使用4-10“正常”否则,如果按选项的频率排序的构造。 二叉树中的最后两个或三个级别不需要太多进展。
概要
至少对这种比较有两种优化。
- 二元决策树
- 由于选项的频率而订购
二进制决策树由编译器用于大型switch-case结构。 但是编译器对选项的频率一无所知。 因此,如果一个或两个选项比其他选项更频繁,则根据频率的排序可以对开关盒的使用具有性能益处。 在这种情况下,这是一个解决方法:
if (action == "opt5") // Processing a frequent (99%) option first { } else // Processing less frequent options (>1%) second { switch( action ) { case "opt1": ... case "opt2": ... } }
警告
在完成分析之前不要优化代码,这是非常必要的。 最好使用switch-case或者 - 如果是直接的,你的代码保持清洁和可读。 如果您已经优化了代码,请在代码中添加一些好的注释,这样每个人都可以理解这种丑陋的代码安静。 一年之后,您将不会知道分析数据,一些评论将非常有用。
如果你发现本机java开关结构太多限制, 请看一下lambdaj Switcher ,它允许通过将它们与一些hamcrest匹配器匹配来声明性地打开任何对象。
请注意,在switch语句的情况下使用字符串是将在下一版本的Java中添加的新function之一。
请参阅项目硬币:交换机中字符串的提议