Jim
Jim

Reputation: 19582

Fastest way to check if comma separated string contains at least 1 valid integer?

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

Answers (4)

Jean Logeart
Jean Logeart

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

Adam Stelmaszczyk
Adam Stelmaszczyk

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.

Results

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

Andreas
Andreas

Reputation: 5103

This is a job for regular expressions.

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

dxdy
dxdy

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

Related Questions