1

What is an efficient way to test in java that in a given string all containing digits are in ascending order?

Example strings might be

String ascending = "Welc2ome T3o Co3mp67uter W99orld";
String notAscending = "Welc8ome T3o Co3mp67uter W99orld";
Bernicc
  • 636
  • 6
  • 14

2 Answers2

3

Avoid using String.split or Integer.parseInt because it not efficient.

If international digits and unicode character should be supported the following might be a solution.

public static boolean isNumericValuesAscending(String s) {
  int max = -1;
  for (int i = 0; i< s.length(); i++) {
      char current = s.charAt(i);
      boolean isDigit = Character.isDigit(current);
      if (isDigit) {
          int currentNumericValue = Character.getNumericValue(current);
          if (max <= currentNumericValue) {
              max = currentNumericValue;
          } else {
              return false;
          }
      }
  }
  return true;
}

If the if condition max <= currentNumericValue is changed to max < currentNumericValue, duplicate numeric values like T3o Co3 and W99orld are not allowed.

Bernicc
  • 636
  • 6
  • 14
1

It can be implemented in a more concise way using Java Streams + AtomicInteger to track previous digit:

public static boolean ascendingDigits(String s) {
    AtomicInteger prev = new AtomicInteger('0');
    return s.chars()
            .mapToObj(c -> (char)c)      // Stream of Character
            .filter(Character::isDigit)  // filter digits including Unicode ranges
            .allMatch(c -> prev.getAndSet(c) <= c);  // compare previous digit to current and update the previous one
}

Test:

String asc = "Welc2ome T3o Co3mp67uter W89orld\uFF10 \uFF15 \uFF17"; // using fullwidth digits
System.out.println(asc);
System.out.println(ascendingDigits(asc));
        
String notAscending = "Welc8ome T3o Co3mp67uter W99orld";
System.out.println(ascendingDigits(notAscending));

Output:

Welc2ome T3o Co3mp67uter W89orld0 5 7
true
false
Nowhere Man
  • 19,170
  • 9
  • 17
  • 42
  • I like the stream / functional aproached, but the use of `Atomic` seems a bit suspicious to me. If atomic integer operations include some memory fences or something like that, perhaps it would be more performant to avoid them? I understand `getAndSet` is nice to keep the code short, but perhaps it would be better to use a bit more verbose ternary operation? – Suma Dec 06 '20 at 15:06
  • I have little Java stream experience, but I use Scala a lot. In Scala I would avoid using the global accumulator and use `foldLeft` to perform the comparison with previous element. I do not know if the stream API has some corresponding functionality, but if it has, I think it might be nicer to use it. – Suma Dec 06 '20 at 15:08
  • @Suma, I think I have even less Scala experience than you do with Java streams. Afaik, yet [there's no direct equivalent of `foldLeft`](https://stackoverflow.com/questions/41240414/equivalent-of-scalas-foldleft-in-java-8) in Java. – Nowhere Man Dec 06 '20 at 16:06