< prev index next >

src/java.base/share/classes/java/util/Comparator.java

Print this page
rev 17656 : [mq]: 8134512-provide-Alpha-Numeric-logical-Comparator

@@ -28,11 +28,10 @@
 import java.io.Serializable;
 import java.util.function.Function;
 import java.util.function.ToIntFunction;
 import java.util.function.ToLongFunction;
 import java.util.function.ToDoubleFunction;
-import java.util.Comparators;
 
 /**
  * A comparison function, which imposes a <i>total ordering</i> on some
  * collection of objects.  Comparators can be passed to a sort method (such
  * as {@link Collections#sort(List,Comparator) Collections.sort} or {@link

@@ -524,11 +523,164 @@
      * @return a comparator that compares by an extracted key
      * @see #comparing(Function)
      * @throws NullPointerException if the argument is null
      * @since 1.8
      */
-    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
+    public static <T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
         Objects.requireNonNull(keyExtractor);
         return (Comparator<T> & Serializable)
             (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
     }
+
+    /**
+     * The returned comparator compares two character sequences as though each
+     * of them would be first transformed into a tuple of the form:
+     * <pre>{@code (A0, N0, A1, N1, ..., An-1, Nn-1, An, Nn)}</pre>
+     * where:
+     * <p>{@code A0} and {@code An} are (possibly empty) sub-sequences
+     * consisting of non-decimal-digit characters,
+     * <p>{@code A1 ... An-1} are non-empty sub-sequences consisting of
+     * non-decimal-digit characters,
+     * <p>{@code N0 ... Nn-1} are non-empty sub-sequences consisting of
+     * decimal-digit characters, and
+     * <p>{@code Nn} is a (possibly empty) sub-sequence consisting of
+     * decimal-digit characters.
+     *
+     * <p>All sub-sequences concatenated together in order as they appear in the
+     * tuple yield the original character sequence.
+     *
+     * After transformation, the tuples are compared by their elements (from
+     * left to right) so that corresponding {@code Ax} elements are compared
+     * using the provided comparator {@code alphaComparator} and {@code Nx}
+     * elements are compared as non negative decimal integers.
+     *
+     * The first pair of compared elements that is different with respect to the
+     * used comparator (either {@code alphaComparator}, or special decimal
+     * comparator) if any, provides the result produced by this comparator.
+     * The arguments are treated equal, if and only if all the subsequences,
+     * both decimal and non-decimal, compare equal.
+     *
+     * <p>For example, the following array was sorted using such comparator:
+     * <pre>{@code
+     * { "1ab", "5ab", "10ab",
+     *   "a1b", "a5b", "a10b",
+     *   "ab1", "ab5", "ab10" };}</pre>
+     *
+     * <p>When comparing numerical parts, an empty character sequence is
+     * considered less than any non-empty sequence of decimal digits.
+     *
+     * <p>If the numeric values of two compared character sub-sequences are
+     * equal, but their string representations have different number of leading
+     * zeroes, the comparator treats the number with less leading zeros as
+     * smaller.
+     * For example, {@code "abc 1" < "abc 01" < "abc 001"}.
+     *
+     * @apiNote  For example, to sort a collection of {@code String} based on
+     * case-insensitive ordering, and treating numbers with more leading
+     * zeroes as greater, one could use
+     *
+     * <pre>{@code
+     *     Comparator<String> cmp = Comparator.comparingAlphaDecimal(
+     *             Comparator.comparing(CharSequence::toString,
+     *                                  String::compareToIgnoreCase));
+     * }</pre>
+     *
+     * @implSpec  To test if the given code point represents a decimal digit,
+     * the comparator checks if {@link java.lang.Character#getType(int)}
+     * returns value {@link java.lang.Character#DECIMAL_DIGIT_NUMBER}.
+     * The comparator uses {@link java.lang.Character#digit(int, int)} with
+     * the second argument set to {@code 10} to determine the numeric
+     * value of a digit represented by the given code point.
+     *
+     * @param  alphaComparator the comparator that compares sub-sequences
+     *                         consisting of non-decimal-digits
+     * @param  <T> the type of elements to be compared; normally
+     *                         {@link java.lang.CharSequence}
+     * @return a comparator that compares character sequences, following the
+     *                         rules described above
+     * @throws NullPointerException if the argument is null
+     *
+     * @since 10
+     */
+    public static <T extends CharSequence> Comparator<T>
+    comparingAlphaDecimal(Comparator<? super CharSequence> alphaComparator) {
+        return new Comparators.AlphaDecimalComparator<>(
+                Objects.requireNonNull(alphaComparator), false);
+    }
+
+    /**
+     * The returned comparator compares two character sequences as though each
+     * of them would be first transformed into a tuple of the form:
+     * <pre>{@code (A0, N0, A1, N1, ..., An-1, Nn-1, An, Nn)}</pre>
+     * where:
+     * <p>{@code A0} and {@code An} are (possibly empty) sub-sequences
+     * consisting of non-decimal-digit characters,
+     * <p>{@code A1 ... An-1} are non-empty sub-sequences consisting of
+     * non-decimal-digit characters,
+     * <p>{@code N0 ... Nn-1} are non-empty sub-sequences consisting of
+     * decimal-digit characters, and
+     * <p>{@code Nn} is a (possibly empty) sub-sequence consisting of
+     * decimal-digit characters.
+     *
+     * <p>All sub-sequences concatenated together in order as they appear in the
+     * tuple yield the original character sequence.
+     *
+     * After transformation, the tuples are compared by their elements (from
+     * left to right) so that corresponding {@code Ax} elements are compared
+     * using the provided comparator {@code alphaComparator} and {@code Nx}
+     * elements are compared as non negative decimal integers.
+     *
+     * The first pair of compared elements that is different with respect to the
+     * used comparator (either {@code alphaComparator}, or special decimal
+     * comparator) if any, provides the result produced by this comparator.
+     * The arguments are treated equal, if and only if all the subsequences,
+     * both decimal and non-decimal, compare equal.
+     *
+     * <p>For example, the following array was sorted using such comparator:
+     * <pre>{@code
+     * { "1ab", "5ab", "10ab",
+     *   "a1b", "a5b", "a10b",
+     *   "ab1", "ab5", "ab10" };}</pre>
+     *
+     * <p>When comparing numerical parts, an empty character sequence is
+     * considered less than any non-empty sequence of decimal digits.
+     *
+     * <p>If the numeric values of two compared character sub-sequences are
+     * equal, but their string representations have different number of leading
+     * zeroes, the comparator treats the number with more leading zeros as
+     * smaller.
+     * For example, {@code "abc 001" < "abc 01" < "abc 1"}.
+     *
+     * @apiNote  For example, to sort a collection of {@code String} based on
+     * case-insensitive ordering, and treating numbers with less leading
+     * zeroes as greater, one could use
+     *
+     * <pre>{@code
+     *       Comparator<String> cmp = Comparator.comparingAlphaDecimalLeadingZeroesFirst(
+     *             Comparator.comparing(CharSequence::toString,
+     *                                  String::compareToIgnoreCase));
+     * }</pre>
+     *
+     * @implSpec  To test if the given code point represents a decimal digit,
+     * the comparator checks if {@link java.lang.Character#getType(int)}
+     * returns value {@link java.lang.Character#DECIMAL_DIGIT_NUMBER}.
+     * The comparator uses {@link java.lang.Character#digit(int, int)} with
+     * the second argument set to {@code 10} to determine the numeric
+     * value of a digit represented by the given code point.
+     *
+     * @param  alphaComparator the comparator that compares sub-sequences
+     *                         consisting of non-decimal-digits
+     * @param  <T> the type of elements to be compared; normally
+     *                         {@link java.lang.CharSequence}
+     * @return a comparator that compares character sequences, following the
+     *                         rules described above
+     * @throws NullPointerException if the argument is null
+     *
+     * @since 10
+     */
+    public static <T extends CharSequence> Comparator<T>
+    comparingAlphaDecimalLeadingZeroesFirst(
+            Comparator<? super CharSequence> alphaComparator) {
+        return new Comparators.AlphaDecimalComparator<>(
+                Objects.requireNonNull(alphaComparator), true);
+    }
 }
< prev index next >