我需要将String(有效整数)与int值进行比较。
对于String str
,int integer
,我的选项是:
Integer.parseInt(str) == integer
str.equals(Integer.toString(integer))
哪一个更快,有没有更好的方法?
以下是受到atlaste的回答的EqualsIntString的启发
private static boolean checkEquality(final String string, final long value) {
if (string == null) {
return false;
}
final int length = string.length();
if (length == 0) {
return false;
}
long absValue;
final byte minIndex;
if (string.charAt(0) == '-') {
if (value > 0) {
return false;
}
absValue = -value;
minIndex = 1;
} else {
if (value < 0) {
return false;
}
absValue = value;
if (string.charAt(0) == '+') {
minIndex = 1;
} else {
minIndex = 0;
}
}
for (int idx = length - 1; idx >= minIndex; idx--) {
final byte rem = (byte) (absValue % 10);
absValue /= 10;
final int diff = string.charAt(idx) - rem - 48;
if (diff != 0) {
return false;
}
}
return absValue == 0;
}
答案 0 :(得分:4)
只有一种方法可以知道:衡量。
快速JMH基准测试显示Integer.parseInt
更快,无论整数的大小如何。但我们谈论的是大约10纳秒左右,并且它不太可能在您的应用程序级别上产生太大的影响。
如果你 100% 确定你的字符串是一个有效的整数,你也可以手动解析它,这会更快(参见{{1}以及下面代码中的parseManual
方法。使用哪种方法还取决于您是否期望值通常相等或经常不同(如果它们通常相等,equalsIntString
效果更好,如果您希望它们平均不同,parseManual
是快)。
因此,数据集的特征在决策中也很重要。
完整结果(得分为每个操作的纳秒数:越小越好) - equalsIntString
列是要比较的整数。第一部分是相等的值,第二部分是不等的值。
(n)
代码:
Benchmark (n) Mode Samples Score Error Units
c.a.p.SO30507506.manual 1 avgt 10 6.579 ± 0.131 ns/op
c.a.p.SO30507506.manual 12345 avgt 10 10.017 ± 0.401 ns/op
c.a.p.SO30507506.manual 123456789 avgt 10 12.490 ± 0.243 ns/op
c.a.p.SO30507506.manualAtlaste 1 avgt 10 7.914 ± 0.144 ns/op
c.a.p.SO30507506.manualAtlaste 12345 avgt 10 15.902 ± 0.593 ns/op
c.a.p.SO30507506.manualAtlaste 123456789 avgt 10 28.117 ± 0.463 ns/op
c.a.p.SO30507506.parse 1 avgt 10 8.495 ± 0.325 ns/op
c.a.p.SO30507506.parse 12345 avgt 10 21.614 ± 0.564 ns/op
c.a.p.SO30507506.parse 123456789 avgt 10 34.692 ± 0.572 ns/op
c.a.p.SO30507506.stringEquals 1 avgt 10 21.597 ± 0.594 ns/op
c.a.p.SO30507506.stringEquals 12345 avgt 10 36.948 ± 1.144 ns/op
c.a.p.SO30507506.stringEquals 123456789 avgt 10 44.444 ± 1.011 ns/op
c.a.p.SO30507506.manual_unequal 1 avgt 10 7.011 ± 0.149 ns/op
c.a.p.SO30507506.manual_unequal 12345 avgt 10 10.244 ± 0.350 ns/op
c.a.p.SO30507506.manual_unequal 123456789 avgt 10 13.135 ± 0.797 ns/op
c.a.p.SO30507506.manualAtlaste_unequal 1 avgt 10 4.328 ± 0.111 ns/op
c.a.p.SO30507506.manualAtlaste_unequal 12345 avgt 10 4.359 ± 0.115 ns/op
c.a.p.SO30507506.manualAtlaste_unequal 123456789 avgt 10 4.339 ± 0.103 ns/op
c.a.p.SO30507506.parse_unequal 1 avgt 10 8.304 ± 0.251 ns/op
c.a.p.SO30507506.parse_unequal 12345 avgt 10 21.514 ± 0.405 ns/op
c.a.p.SO30507506.parse_unequal 123456789 avgt 10 35.257 ± 1.043 ns/op
c.a.p.SO30507506.stringEquals_unequal 1 avgt 10 19.060 ± 0.162 ns/op
c.a.p.SO30507506.stringEquals_unequal 12345 avgt 10 31.829 ± 0.427 ns/op
c.a.p.SO30507506.stringEquals_unequal 123456789 avgt 10 41.870 ± 0.252 ns/op
答案 1 :(得分:1)
有趣的问题。为清楚起见,测试这个问题可能会有很多错误,因为Java会使用可能影响结果的字符串。因此,让我们开始构建一个合适的测试。
构建测试
具体来说:正确的测试并不依赖于loadstring,因为这会影响内存分配。您想使用动态构造的字符串进行测试。
整数的10-log(例如字符串的长度)将影响测试结果。字符串越长,Integer.tryParse
将越长。如果你有一个更长的字符串,它将需要计算更多的div / mul并需要更长的时间。影响性能的另一个因素是&#39; - &#39;标志。如果您有无符号整数,则应将其考虑在内。
基本上测量意味着:
确保在测试期间为此制作一个巨大的数组,以便您的测试不会受到影响。还要确保你使用的整数/随机数与你的数据具有相同的特征......因此,我不能为你执行测试,所以我只是坚持理论。
字符串到整数相等
了解字符串到整数转换的工作方式很有帮助,所以让我们从一个直接的解决方案开始,然后继续努力。我目前在笔记本电脑上没有Java,所以我很抱歉C#语法:-)你应该能够轻松解决它... ...
public int ConvertStringToInt(string s)
{
int val = 0;
if (s[0] == '-') // 1
{
for (int i = 1; i < s.Length; ++i )
{
if (s[i] >= '0' && s[i] <= '9') // 2
{
throw new Exception();
}
val = val * 10 + s[i] - '0';
}
return -val;
}
else
{
for (int i = 0; i < s.Length; ++i)
{
if (s[i] >= '0' && s[i] <= '9')
{
throw new Exception();
}
val = val * 10 + s[i] - '0';
}
return val;
}
}
如果您知道字符串中的数字永远不会为负数,那么您当然可以放弃条件 1 。此外,如果您知道该字符串始终是一个数字(在您的问题中隐含的是IMO),您可以优化 2 。我通常使用的一个小技巧是使用算术溢出来生成大的无符号数,从而从 2 中删除一个附加条件。你最终会得到:
public int ConvertStringToInt(string s)
{
int val = 0;
if (s[0] == '-')
{
for (int i = 1; i < s.Length; ++i )
{
val = val * 10 + s[i] - '0';
}
return -val;
}
else
{
for (int i = 0; i < s.Length; ++i)
{
val = val * 10 + s[i] - '0';
}
return val;
}
}
接下来,你想要平等而不是转换。那么,我们对这个有多懒惰呢?好吧,在我们进行检查之前,我们需要解析几乎所有的字符串。我们唯一知道的是,如果我们遇到一个&#39; - &#39; char,我们还需要一个负整数。我最终得到了这个:
public bool EqualsStringInt(string s, int value)
{
int val = 0;
if (s[0] == '-')
{
if (value >= 0) { return false; } // otherwise we expected another char
for (int i = 1; i < s.Length; ++i )
{
val = val * 10 + s[i] - '0'; // s[i] must be a char between '0'-'9' as implied by the question.
}
return (-val) == value;
}
else
{
if (value < 0) { return false; } // otherwise we expected another char
for (int i = 0; i < s.Length; ++i)
{
val = val * 10 + s[i] - '0';
}
return val == value;
}
}
字符串相等的整数
我过去为C ++编写了一些代码,它将整数转换为字符串:C++ performance challenge: integer to std::string conversion。如果您真的在寻找性能,那么这里也有一些很好的解决方案可能值得考虑。
只是检查平等比这更容易。如果仔细查看算法,您会注意到:
从长远来看,这两者都应该耗费时间,而且它们都会影响你的测试。
在这一点上,有趣的是你注意到你并不需要完整的字符串 - 你只需要一个字符。所以,让我们使用它:
或者,在代码中:
public bool EqualsIntString(int value, string s)
{
if (s.Length == 0) { return false; } // This is never good.
if ((s[0] == '-' && value >= 0) || (s[0] != '-' && value < 0)) { return false; } // positive/negative check
// Define the limit. This is basically the end of the string to check.
int limit = 0;
if (value < 0) // 1
{
limit = 1;
value = -value;
}
for (int i=s.Length-1; i>=limit; --i)
{
char expected = (char)('0' + (value % 10)); // the modulo will be optimized by the JIT because 10 is a constant
value /= 10; // same story.
if (s[i] != expected) { return false; }
}
return true;
}
同样,如果您没有负数,请进行明显的优化。删除 1 。
你能做得更快吗?是的......那就是我首先发布C ++链接的原因。大多数这些算法都可以轻松调整,以实现这种平等。情况下。
上一个解决方案的可选优化
您可以使用10log来确定字符串的长度。这意味着整数的下限值和上限值。一个简单的查找表可以为您完成此操作。但是,如果没有正确实现,10log很慢,所以一定要测试一下!
哪一个更快
构建一个合适的测试,并测试它。我试图在这里进行测试,但不具备您的数据特征,我希望这些特性会有所作为。
当然,如果你不需要这么直率的表现,请使用标准的实现和等号,并测试它。
答案 2 :(得分:0)
我敢打赌
Integer.parseInt(str) == integer
更快。所需要的只是一个乘法和每个数字一个加法,而Integer.toString
需要除法和每个数字的模数 - 最慢的算术运算。
实际上,有一些优化可以减少Integer.toString
中的操作次数,但速度比太大了。
此外,还有新字符串的内存分配。
OTOH,Integer.parseInt
接受所有的Unicode数字,而不仅仅是0到9,这会大大减慢它的速度。我猜,番石榴的Ints.parseInt
速度更快。
如果无法解析字符串,那么您将获得NumberFormatException
。你可以捕获它,但它需要花费很多时间,然后Integer.toString
才是赢家。
答案 3 :(得分:-1)
我会选择Interger.Parse(),面对不同的本地化文化等,它可能比其他方法更具弹性......
速度不是真正的问题 - 有效的结果是。