Ree*_*sen 6 java algorithm performance switch-statement
更新:
我的实用程序的最终版本如下所示:
StringBuilder b = new StringBuilder();
for(char c : inLetters.toLowerCase().toCharArray())
{
switch(c)
{
case '0': b.append("0"); break;
case '1': b.append("1"); break;
case '2': case 'a': case 'b': case 'c': b.append("2"); break;
case '3': case 'd': case 'e': case 'f': b.append("3"); break;
case '4': case 'g': case 'h': case 'i': b.append("4"); break;
case '5': case 'j': case 'k': case 'l': b.append("5"); break;
case '6': case 'm': case 'n': case 'o': b.append("6"); break;
case '7': case 'p': case 'q': case 'r': case 's': b.append("7"); break;
case '8': case 't': case 'u': case 'v': b.append("8"); break;
case '9': case 'w': case 'x': case 'y': case 'z': b.append("9"); break;
}
}
return builder.toString();
Run Code Online (Sandbox Code Playgroud)
原始问题:
我正在承担将字母数字电话号码转换为数字串的简单任务.例如,1-800-HI-HAXOR将变为1-800-44-42967.我最初的尝试是创建一个讨厌的开关声明,但我喜欢一个更优雅,更有效的解决方案.这是我得到的:
for(char c : inLetters.toLowerCase().toCharArray())
{
switch(c)
{
case '0': result+="0"; break;
case '1': result+="1"; break;
case '2': case 'a': case 'b': case 'c': result+="2"; break;
case '3': case 'd': case 'e': case 'f': result+="3"; break;
case '4': case 'g': case 'h': case 'i': result+="4"; break;
case '5': case 'j': case 'k': case 'l': result+="5"; break;
case '6': case 'm': case 'n': case 'o': result+="6"; break;
case '7': case 'p': case 'q': case 'r': case 's': result+="7"; break;
case '8': case 't': case 'u': case 'v': result+="8"; break;
case '9': case 'w': case 'x': case 'y': case 'z': result+="9"; break;
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
switch语句并不是那么糟糕.您的算法与电话号码的长度成线性关系.代码是可读的,很容易通过检查验证.除了添加default处理错误的案例之外,我不会惹它.(我不是Java程序员,所以请原谅我,如果它被称为其他东西.)
如果必须加快速度,则按字符索引的预初始化表将避免除基本错误检查之外的任何比较.您甚至可以通过复制表(digit['A'] = digit['a'] = "2";)中的值来避免大小写转换.初始化表的成本将按总转化次数摊销.
您可以使用Apache Commons Lang StringUtils执行此操作,如下所示:
String output = StringUtils.replaceChars(StringUtils.lowerCase(input),
"abcdefghijklmnopqrstuvwxyz",
"22233344455566677778889999");
Run Code Online (Sandbox Code Playgroud)
当然,假设速度不是您的主要考虑因素,并且您需要一个紧凑的解决方案;)
使用a Map,其中键是字母和数字,值是键盘上的数字.(因此每个键盘编号将被三个或四个字母和一个数字编入索引).
Map<Character, Character> keypad = new HashMap<Character, Character>();
...
StringBuilder buf = new StringBuilder(inLetters.length());
for (int idx = 0; idx < inLetters.length(); ++idx) {
Character ch = keypad.get(inLetters.charAt(idx));
if (ch != null)
buf.append(ch);
}
Run Code Online (Sandbox Code Playgroud)
更新:我很好奇手动编码的查找表是否比密集的switch案例表现更好.在我的临时测试中,我发现以下代码是我能想到的最快的代码:
private static final char[] lut =
"0123456789:;<=>?@22233344455566677778889999[\\]^_`22233344455566677778889999".toCharArray();
private static final char min = lut[0];
String fastest(String letters)
{
int n = letters.length();
char[] buf = new char[n];
while (n-- > 0) {
int ch = letters.charAt(n) - min;
buf[n] = ((ch < 0) || (ch >= lut.length)) ? letters.charAt(n) : lut[ch];
}
return new String(buf);
}
Run Code Online (Sandbox Code Playgroud)
令人惊讶的是,它的速度是使用switch语句(编译为tableswitch指令)的类似代码的两倍多.这只是为了好玩,请注意,但在我的笔记本电脑上,在一个线程中运行,我可以在大约1.3秒内转换1000万个10个字母的"数字".我真的很惊讶,因为根据我的理解,它tableswitch以基本相同的方式运行,但我预计它会更快,因为它是一个JVM指令.
当然,除非我只收到我可以转换的无限电话号码的每一笔付款,否则我绝不会写这样的代码.交换机更具可读性,运行良好,并且可能在未来的某些JVM中获得免费的性能提升.
远远地,对原始代码的最大改进来自于使用StringBuilder而不是连接字符串,并且这不会损害代码的可读性.使用charAt而不是将输入转换为a char[]也使代码更简单,更容易理解 并提高性能.最后,附加char文字而不是String文字('1'而不是文字"1")是一种性能改进,有助于提高可读性.