java 摆脱丑陋的 if 语句
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3786358/
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
Get rid of ugly if statements
提问by kofucii
I have this ugly code:
我有这个丑陋的代码:
if ( v > 10 ) size = 6;
if ( v > 22 ) size = 5;
if ( v > 51 ) size = 4;
if ( v > 68 ) size = 3;
if ( v > 117 ) size = 2;
if ( v > 145 ) size = 1;
return size;
How can I get rid of the multiple if statements?
如何摆脱多个 if 语句?
回答by mfloryan
How about such approach:
这种方法怎么样:
int getSize(int v) {
int[] thresholds = {145, 117, 68, 51, 22, 10};
for (int i = 0; i < thresholds.length; i++) {
if (v > thresholds[i]) return i+1;
}
return 1;
}
Functionally: (Demonstrated in Scala)
功能上:(在 Scala 中演示)
def getSize(v: Int): Int = {
val thresholds = Vector(145, 117, 68, 51, 22, 10)
thresholds.zipWithIndex.find(v > _._1).map(_._2).getOrElse(0) + 1
}
回答by barjak
Using the NavigableMap
API :
使用NavigableMap
API :
NavigableMap<Integer, Integer> s = new TreeMap<Integer, Integer>();
s.put(10, 6);
s.put(22, 5);
s.put(51, 4);
s.put(68, 3);
s.put(117, 2);
s.put(145, 1);
return s.lowerEntry(v).getValue();
回答by Alexander Torstling
The most obvious problem with the OPs solution is branching, so I would suggest a polynomial regression. This will result in a nice branchless expression on the form
OPs 解决方案最明显的问题是分支,所以我建议使用多项式回归。这将在表单上产生一个很好的无分支表达式
size = round(k_0 + k_1 * v + k_2 * v^2 + ...)
You will of course not get an exact result, but if you can tolerate some deviance it's a very performant alternative. Since the 'leave unmodified' behavior of to original function for values where v<10
is impossible to model with a polynomial, I took the liberty of assuming a zero-order hold interpolation for this region.
您当然不会得到确切的结果,但如果您可以容忍一些偏差,那么这是一个非常高效的替代方案。由于对于v<10
不可能用多项式建模的值的原始函数的“保持不变”行为,我冒昧地假设该区域的零阶保持插值。
For a 45-degree polynomial with the following coefficients,
对于具有以下系数的 45 度多项式,
-9.1504e-91 1.1986e-87 -5.8366e-85 1.1130e-82 -2.8724e-81 3.3401e-78 -3.3185e-75 9.4624e-73 -1.1591e-70 4.1474e-69 3.7433e-67 2.2460e-65 -6.2386e-62 2.9843e-59 -7.7533e-57 7.7714e-55 1.1791e-52 -2.2370e-50 -4.7642e-48 3.3892e-46 3.8656e-43 -6.0030e-41 9.4243e-41 -1.9050e-36 8.3042e-34 -6.2687e-32 -1.6659e-29 3.0013e-27 1.5633e-25 -8.7156e-23 6.3913e-21 1.0435e-18 -3.0354e-16 3.8195e-14 -3.1282e-12 1.8382e-10 -8.0482e-09 2.6660e-07 -6.6944e-06 1.2605e-04 -1.7321e-03 1.6538e-02 -1.0173e-01 8.3042e-34 -6.2687e-32 -1.6659e-29 3.0013e-27 1.5633e-25 -8.7156e-23 6.3913e-21 1.0435e-18 -3.0354e-16 3.8195e-14 -3.1282e-12 1.8382e-10 -8.0482e-09 2.6660e-07 -6.6944e-06 1.2605e-04 -1.7321e-03 1.6538e-02 -1.0173e-01 3.6100e-01 -6.2117e-01 6.3657e+00
, you get a beautifully fitted curve:
,你会得到一个漂亮的拟合曲线:
And as you can see, you get an 1-norm error of just 1.73 across the whole range from 0 to 200*!
正如您所看到的,在 0 到 200* 的整个范围内,您得到的 1 范数误差仅为 1.73!
*Results for v?[0,200]
may vary.
*结果v?[0,200]
可能会有所不同。
回答by Jigar Joshi
if ( v > 145 ) size = 1;
else if ( v > 117 ) size = 2;
else if ( v > 68 ) size = 3;
else if ( v > 51 ) size = 4;
else if ( v > 22 ) size = 5;
else if ( v > 10 ) size = 6;
return size;
This is better for your case.
这更适合你的情况。
Optionally you should choose Switch Case where ever possible
或者,您应该尽可能选择 Switch Case
Update:
If you have analyzed the value of 'v' generally resides in lower range(<10) in most of the cases than you can add this.
Update:
如果您已经分析过,在大多数情况下,'v' 的值通常位于较低的范围内(<10),而不是您可以添加它。
if(v < 10) size = SOME_DEFAULT_VALUE;
else if ( v > 145 ) size = 1;
else if ( v > 117 ) size = 2;
else if ( v > 68 ) size = 3;
else if ( v > 51 ) size = 4;
else if ( v > 22 ) size = 5;
else if ( v > 10 ) size = 6;
further :
You can also alter the condition sequence, according to your analysis. If you know that most of the values are less than 10 and then in the second place most of values lie between 68-117, you can alter the condition sequence accordingly.
further :
您还可以根据您的分析更改条件序列。如果您知道大多数值都小于 10,而其次大多数值位于 68-117 之间,您可以相应地更改条件序列。
Edits:
编辑:
if(v < 10) return SOME_DEFAULT_VALUE;
else if ( v > 145 ) return 1;
else if ( v > 117 ) return 2;
else if ( v > 68 ) return 3;
else if ( v > 51 ) return 4;
else if ( v > 22 ) return 5;
else if ( v > 10 ) return 6;
回答by dhblah
return v > 145 ? 1
: v > 117 ? 2
: v > 68 ? 3
: v > 51 ? 4
: v > 22 ? 5
: v > 10 ? 6
: "put inital size value here";
回答by Jim Ferrans
The original code seems fine to me, but if you don't mind multiple returns you might prefer a more tabular approach:
原始代码对我来说似乎很好,但如果您不介意多次返回,您可能更喜欢更表格的方法:
if ( v > 145 ) return 1;
if ( v > 117 ) return 2;
if ( v > 68 ) return 3;
if ( v > 51 ) return 4;
if ( v > 22 ) return 5;
if ( v > 10 ) return 6;
return ...; // The <= 10 case isn't handled in the original code snippet.
See the multiple return or not discussion in org.life.java's answer.
请参阅org.life.java's answer 中的多次返回或不讨论。
回答by cbmeeks
There are a ton of answers and suggestions here but I honestly don't see any of them "prettier" or "more elegant" than the original method.
这里有大量的答案和建议,但老实说,我没有看到它们中的任何一个比原始方法“更漂亮”或“更优雅”。
If you had dozens or HUNDREDS of iterations to check then I could easily see going to some for loop but honestly, for the handful of comparisons you had, stick with the if's and move on. It's not that ugly.
如果您要检查数十或数百次迭代,那么我可以很容易地看到进行一些 for 循环,但老实说,对于您进行的少数比较,请坚持使用 if 并继续。没那么丑。
回答by mhaller
return (v-173) / -27;
回答by st0le
Here's my shot at it...
这是我的尝试...
Update: Fixed. Previous Solution gave incorrect answers for exact values (10,22,51...). This one defaults to 6 for the if val < 10
更新:固定。先前的解决方案对精确值(10,22,51...)给出了错误的答案。对于 if val < 10,此默认值为 6
static int Foo(int val)
{
//6, 5, 4, 3, 2 ,1
int[] v = new int[]{10,22,51,68,117,145};
int pos = Arrays.binarySearch(v, val-1);
if ( pos < 0) pos = ~pos;
if ( pos > 0) pos --;
return 6-pos;
}
回答by ErikE
I have one more version for you. I don't really think it's the best one because it adds unnecessary complexity in the name of "performance" when I'm 100% sure this function will never be a performance hog (unless someone is calculating size in a tight loop a million times ...).
我还有一个版本给你。我真的不认为它是最好的,因为当我 100% 确定这个函数永远不会成为性能猪时,它以“性能”的名义增加了不必要的复杂性(除非有人在一个紧密的循环中计算大小一百万次……)。
But I present it just because I thought performing a hard-coded binary search to be sort of interesting. It doesn't look very binary-y because there aren't enough elements to go very deep, but it does have the virtue that it returns a result in no more than 3 tests rather than 6as in the original post. The return statements are also in order by size which would help with understanding and/or modification.
但我提出它只是因为我认为执行硬编码的二进制搜索有点有趣。它看起来不是很二进制,因为没有足够的元素可以深入,但它确实有一个优点,它返回的结果不超过 3 个测试,而不是原始帖子中的6 个。返回语句也按大小排序,这将有助于理解和/或修改。
if (v > 68) {
if (v > 145) {
return 1
} else if (v > 117) {
return 2;
} else {
return 3;
}
} else {
if (v > 51) {
return 4;
} else if (v > 22) {
return 5;
} else {
return 6;
}
}