在Java中快速搜索特定字符
这似乎是个有点傻的问题。。也许是的。但是我有一个我经常使用的函数,我想知道这是否是完成这项工作的最快方法。该功能被使用了很多次,因此任何速度的提高实际上都是显而易见的。它所做的只是检查一个字符是否是核苷酸(即:如果一个字符是‘a’、‘T’、‘C’或‘G’)在Java中快速搜索特定字符,java,performance,search,character,Java,Performance,Search,Character,这似乎是个有点傻的问题。。也许是的。但是我有一个我经常使用的函数,我想知道这是否是完成这项工作的最快方法。该功能被使用了很多次,因此任何速度的提高实际上都是显而易见的。它所做的只是检查一个字符是否是核苷酸(即:如果一个字符是‘a’、‘T’、‘C’或‘G’) private static boolean isValidNucleotide(char nucleotide) { nucleotide = Character.toUpperCase(nucleotide); if(nu
private static boolean isValidNucleotide(char nucleotide) {
nucleotide = Character.toUpperCase(nucleotide);
if(nucleotide == 'A') return true;
if(nucleotide == 'T') return true;
if(nucleotide == 'C') return true;
if(nucleotide == 'G') return true;
return false;
}
这是完成这项工作的最快方法吗?或者您认为值得实现某种索引/映射/其他功能(可能是在函数外部执行比较,然后将此文本复制到代码中的几个点上)?在Java中,我真的不是这方面的专家。您可以尝试一个
开关案例,它通常作为小型开关的表查找来实现:
switch(nucleotide) {
case 'A':
case 'T':
case 'C':
case 'G':
return true;
}
return false;
请注意,JVM的JIT可能会使基于if
的代码非常快,如果调用次数足够多。去掉字符。toUpperCase
并检查大写和小写情况,它将显著加快您的功能
private static boolean isValidNucleotide(char nucleotide) {
if(nucleotide == 'A' || nucleotide == 'a') return true;
// Rest of your conditions
return false;
}
我对您的原始函数进行了一个小测试,执行10000000次平均需要80ms
,但当我删除Character.toUpperCase()
并明确检查这两种情况时,只需要40ms
,这是显著的改进
编辑:
使用@Shivam Kalla建议的Map
解决方案平均只需11 ms
。我还没有尝试过,但您可以尝试使用Regex查看性能,最快的(但内存效率最低的255字节还不错!)是这样的:
/* this is static member of class */
static boolean map[] = new boolean[256];
static {
for(int j = 0; j < map.length; j++)
map[j] = false;
/* map your required values true here */
map['A'] = true;
map['T'] = true;
map['C'] = true;
map['G'] = true;
/* make small letter here too */
map['a'] = true;
map['t'] = true;
map['c'] = true;
map['g'] = true;
}
private static boolean isValidNucleotide(char nucleotide) {
/* complexity is just one access to array */
return map[nucleotide];
}
正如@paxdiablo所说,在java中,字符是2个字节而不是1个字节,但您的字符在这个范围内。只需将返回映射[nucleotide];
更改为返回映射[0x00ff&nucleotide];
就可以了
为了安全起见,您还可以将映射的大小更改为65536
,以避免任何类型的错误。boolean map=new boolean[65536]
很有趣,是的,我想知道JVM是否会自行进行此类优化。不过这看起来很可靠。我将尝试一个测试,看看它对运行时有何影响。您还可以尝试通过向开关添加小写字母来替换toUpperCase
调用。检查后,接受的答案很快这个答案也很好,因为它也很快,目的也更明确,这意味着它可能会从JRE的未来优化中获得更多好处。如果字符超过255会发生什么?Java不是天生的Unicode吗?似乎就是这样。我做了一个类似于iTech的测试。令人印象深刻!你应该这样做顺便说一句,也可以将其改为256,索引为0..255。因此,事实上,如果核苷酸高于255,则会出现异常!或者如果您将其屏蔽,则可能会得到错误的答案…这更糟。@paxdiablo谢谢!是的,这很有意义。请后退一步,重新检查实际问题,而不是您的解决方案。它实际上可能是错误的以完全不同的方式更快地完成这项工作,例如,提前限制用户输入,或提前检查整个核苷酸序列,以便以后不再重复检查。甚至可能有理由这样做(如果你更关心速度而不是有效性)根本不检查。@paxdiablo谢谢你的建议。我确实接受了答案,但这些评论确实值得考虑。我确实需要验证,但可能有一种方法可以限制链中早期的输入。尝试将开关(核苷酸)
更改为开关((字节)核苷酸)
我试过了,但没有影响性能,也花了40 ms
地图解决方案更快,因为它略过了一些范围检查。它只在假设输入字符都小于256时起作用。(我的想法是,也许可以说服JIT编译器使用更大的开关表并避免一些错误。)“不必要的”范围测试。这会使测试速度更快。)