Reputation: 19582
I have a String with comma separated positive integers, for example:
1,34,433,12
What is the fastest way to determine if the string contains at least 1 integer?
Right now I split(",")
, loop over the resulting String[]
and try to parse each element as an int.
This works in order to get a List<Integer>
of the String but I want the fastest way possible to determine if the String is valid for this.
1a,2b,13
is acceptable. 1a,2b,13c
is not acceptable.
Upvotes: 1
Views: 7149
Reputation: 53839
Try:
public static boolean containsInt(String string) {
boolean onlyDigits = true;
boolean atLeastOneDigit = false;
int len = string.length();
for (int i = 0; i < len; i++) {
char c = string.charAt(i);
if (c == ',') {
if (atLeastOneDigit && onlyDigits) {
return true;
}
onlyDigits = true;
atLeastOneDigit = false;
continue;
}
boolean isDigit = c >= '0' && c <= '9';
onlyDigits &= isDigit;
atLeastOneDigit |= isDigit;
}
return atLeastOneDigit && onlyDigits;
}
Now, a more readable version using Guava:
public static boolean containsInt(String text) {
for (String s : Splitter.on(',').split(text) {
if (Ints.tryParse(s) != null)
return true;
}
return false;
}
Upvotes: 3
Reputation: 19847
I've tested solutions proposed by Jim (OP), Jean and Andreas (with compiling the pattern only once out of the loop).
Source code of test. I used jmh.
Benchmark Mode Cnt Score Error Units
MyBenchmark.testJim thrpt 20 32.895 ± 0.708 ops/s
MyBenchmark.testJean thrpt 20 2806.981 ± 31.295 ops/s
MyBenchmark.testAndreas thrpt 20 41.789 ± 6.033 ops/s
Jean's solution is definitely the fastest. I cannot think of anything faster in Java.
Upvotes: 2
Reputation: 5103
About 90% of the time when you see .toCharArray()
someone is reinventing regular expressions. Don't reinvent the wheel!
public class Jim {
public static void main(String... args) {
final String[] strings = new String[]{
//valid
"1,34,433,12",
"12,safdg,sfdg",
"asfd,asdf,12",
"asfd,10,jrtj",
"12356",
",12356,",
//invalid
"asdf",
"1a,2b,13c",
",asdf,",
",,,",
"",
};
for (String s : strings) {
System.out.println(String.format("data: [%s], outcome: [%s]", s, hasNumericField(s)));
}
}
//\A matches the start of the input, thus
//(\A|,) matches the start of the input or a comma, thus
//(\z|,) works the same way but with the end of the input.
//\d+ matches one or more digits.
private static final Pattern pat = Pattern.compile("(\\A|,)\\d+(\\z|,)");
private static boolean hasNumericField(final String commaSeparatedData) {
return pat.matcher(commaSeparatedData).find();
}
}
One of the joys of regular expressions is that it adapts well to changes in input. You just change the expression. If you hand code something you'll likely need to rework -> test -> debug it if the inputs change.
Upvotes: 0
Reputation: 540
Since your String only needs to contain at least a single number, why not iterate over it and check if there is at least one digit (0-9), and whether there are any non number/comma symbols in there?
Upvotes: 0