This is an automated email from the ASF dual-hosted git repository.
paulk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
The following commit(s) were added to refs/heads/master by this push:
new c45c74ebdd GROOVY-11891: Groovy could provide DGM/ADM isSorted variants
c45c74ebdd is described below
commit c45c74ebdd6342208bec3208ce1ec03899f6a742
Author: Paul King <[email protected]>
AuthorDate: Tue Mar 31 21:40:56 2026 +1000
GROOVY-11891: Groovy could provide DGM/ADM isSorted variants
---
.../groovy/runtime/ArrayGroovyMethods.java | 60 ++++++++
.../groovy/runtime/DefaultGroovyMethods.java | 170 +++++++++++++++++++++
2 files changed, 230 insertions(+)
diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
b/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
index e2cecd6e6c..24f1a17e04 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
@@ -5122,6 +5122,66 @@ public class ArrayGroovyMethods extends
DefaultGroovyMethodsSupport {
return result;
}
+
//--------------------------------------------------------------------------
+ // isSorted
+
+ /**
+ * Determines if the array is sorted in natural order using a {@link
NumberAwareComparator}.
+ * <pre class="groovyTestCase">
+ * Integer[] nums = [1, 2, 3]
+ * assert nums.isSorted()
+ * Integer[] unsorted = [3, 1, 2]
+ * assert !unsorted.isSorted()
+ * </pre>
+ *
+ * @param self the array to check
+ * @return true if the array elements are sorted in non-descending order
+ * @see #isSorted(Object[], Comparator)
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(T[] self) {
+ return isSorted(self, new NumberAwareComparator<>());
+ }
+
+ /**
+ * Determines if the array is sorted according to the given Comparator.
+ * This is efficient — it checks adjacent pairs in a single pass and
+ * short-circuits on the first out-of-order pair.
+ * <pre class="groovyTestCase">
+ * String[] words = ["hello","Hey","hi"]
+ * assert words.isSorted(String.CASE_INSENSITIVE_ORDER)
+ * </pre>
+ *
+ * @param self the array to check
+ * @param comparator a Comparator used for the comparison
+ * @return true if the array elements are sorted according to the
comparator
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(T[] self, Comparator<? super T>
comparator) {
+ for (int i = 1; i < self.length; i++) {
+ if (comparator.compare(self[i - 1], self[i]) > 0) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Determines if the array is sorted using the given Closure to determine
order.
+ * <p>
+ * If the Closure has two parameters it is used like a traditional
Comparator.
+ * Otherwise, the Closure is assumed to take a single parameter and return
a
+ * Comparable (typically an Integer) which is then used for further
comparison.
+ *
+ * @param self the array to check
+ * @param closure a 1 or 2 arg Closure used to determine the ordering
+ * @return true if the array elements are sorted according to the closure
+ * @see #isSorted(Object[], Comparator)
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(T[] self,
@ClosureParams(value=FromString.class, options={"T","T,T"}) Closure<?> closure)
{
+ Comparator<T> comparator = (closure.getMaximumNumberOfParameters() ==
1) ? new OrderBy<>(closure) : new ClosureComparator<>(closure);
+ return isSorted(self, comparator);
+ }
+
//--------------------------------------------------------------------------
// iterator
diff --git
a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index b9b2e348ac..b214482c9e 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -9657,6 +9657,176 @@ public class DefaultGroovyMethods extends
DefaultGroovyMethodsSupport {
return !isCase(caseValue, switchValue);
}
+
//--------------------------------------------------------------------------
+ // isSorted
+
+ /**
+ * Determines if the Iterable is sorted. Assumes the elements are
+ * comparable and uses a {@link NumberAwareComparator} to determine the
order.
+ * <pre class="groovyTestCase">
+ * assert [1, 2, 3].isSorted()
+ * assert !([3, 1, 2].isSorted())
+ * assert [].isSorted()
+ * </pre>
+ *
+ * @param self the Iterable to check
+ * @return true if the elements are sorted in non-descending order
+ * @see #isSorted(Iterable, Comparator)
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(Iterable<T> self) {
+ return isSorted(self, new NumberAwareComparator<>());
+ }
+
+ /**
+ * Determines if the Iterable is sorted according to the given Comparator.
+ * This is efficient — it checks adjacent pairs in a single pass and
+ * short-circuits on the first out-of-order pair.
+ * {@code SortedSet} instances always return {@code true}.
+ * <pre class="groovyTestCase">
+ * assert ["hello","Hey","hi"].isSorted(String.CASE_INSENSITIVE_ORDER)
+ * assert !(["hi","Hey","hello"].isSorted(String.CASE_INSENSITIVE_ORDER))
+ * assert (new TreeSet(["c","a","b"])).isSorted()
+ * </pre>
+ *
+ * @param self the Iterable to check
+ * @param comparator a Comparator used for the comparison
+ * @return true if the elements are sorted according to the comparator
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(Iterable<T> self, Comparator<? super T>
comparator) {
+ if (self instanceof SortedSet) return true;
+ return isSorted(self.iterator(), comparator);
+ }
+
+ /**
+ * Determines if the Iterable is sorted using the given Closure to
determine order.
+ * <p>
+ * If the Closure has two parameters it is used like a traditional
Comparator.
+ * Otherwise, the Closure is assumed to take a single parameter and return
a
+ * Comparable (typically an Integer) which is then used for further
comparison.
+ * <pre class="groovyTestCase">
+ * assert ["hi","hey","hello"].isSorted { it.length() }
+ * assert !["hello","hi","hey"].isSorted { it.length() }
+ * assert ["hi","hey","hello"].isSorted { a, b {@code ->} a.length()
{@code <=>} b.length() }
+ * </pre>
+ *
+ * @param self the Iterable to check
+ * @param closure a 1 or 2 arg Closure used to determine the ordering
+ * @return true if the elements are sorted according to the closure
+ * @see #isSorted(Iterable, Comparator)
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(Iterable<T> self,
@ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+ Comparator<T> comparator = (closure.getMaximumNumberOfParameters() ==
1) ? new OrderBy<>(closure) : new ClosureComparator<>(closure);
+ return isSorted(self, comparator);
+ }
+
+ /**
+ * Determines if the Iterator elements are sorted. Assumes the elements are
+ * comparable and uses a {@link NumberAwareComparator} to determine the
order.
+ * <p>
+ * The iterator will be exhausted of elements after determining the sorted
status.
+ *
+ * @param self the Iterator to check
+ * @return true if the elements are sorted in non-descending order
+ * @see #isSorted(Iterator, Comparator)
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(Iterator<T> self) {
+ return isSorted(self, new NumberAwareComparator<>());
+ }
+
+ /**
+ * Determines if the Iterator elements are sorted according to the given
Comparator.
+ * This is efficient — it checks adjacent pairs and short-circuits on the
first
+ * out-of-order pair. The iterator will be exhausted only if the elements
are sorted.
+ *
+ * @param self the Iterator to check
+ * @param comparator a Comparator used for the comparison
+ * @return true if the elements are sorted according to the comparator
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(Iterator<T> self, Comparator<? super T>
comparator) {
+ if (!self.hasNext()) return true;
+ T prev = self.next();
+ while (self.hasNext()) {
+ T curr = self.next();
+ if (comparator.compare(prev, curr) > 0) return false;
+ prev = curr;
+ }
+ return true;
+ }
+
+ /**
+ * Determines if the Iterator elements are sorted using the given Closure
to determine order.
+ * <p>
+ * If the Closure has two parameters it is used like a traditional
Comparator.
+ * Otherwise, the Closure is assumed to take a single parameter and return
a
+ * Comparable which is then used for further comparison.
+ * <p>
+ * The iterator will be exhausted of elements after determining the sorted
status.
+ *
+ * @param self the Iterator to check
+ * @param closure a 1 or 2 arg Closure used to determine the ordering
+ * @return true if the elements are sorted according to the closure
+ * @see #isSorted(Iterator, Comparator)
+ * @since 6.0.0
+ */
+ public static <T> boolean isSorted(Iterator<T> self,
@ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+ Comparator<T> comparator = (closure.getMaximumNumberOfParameters() ==
1) ? new OrderBy<>(closure) : new ClosureComparator<>(closure);
+ return isSorted(self, comparator);
+ }
+
+ /**
+ * Determines if the Map entries are sorted.
+ * Assumes the entries are comparable and uses a {@link
NumberAwareValueComparator}
+ * to determine the order. The map's iteration order is checked.
+ * <pre class="groovyTestCase">
+ * def map = new LinkedHashMap([b:3, d:4, a:5, c:6])
+ * assert map.isSorted()
+ * </pre>
+ *
+ * @param self the Map to check
+ * @return true if the map entries are sorted in non-descending order
+ * @since 6.0.0
+ */
+ public static <K, V> boolean isSorted(Map<K, V> self) {
+ return isSorted(self, new NumberAwareValueComparator<>());
+ }
+
+ /**
+ * Determines if the Map entries are sorted according to the given
Comparator.
+ * The map's iteration order is checked.
+ * {@code SortedMap} instances always return {@code true}.
+ *
+ * @param self the Map to check
+ * @param comparator a Comparator used to compare Map.Entry instances
+ * @return true if the map entries are sorted according to the comparator
+ * @since 6.0.0
+ */
+ public static <K, V> boolean isSorted(Map<K, V> self,
Comparator<Map.Entry<K, V>> comparator) {
+ if (self instanceof SortedMap) return true;
+ return isSorted(self.entrySet(), comparator);
+ }
+
+ /**
+ * Determines if the Map entries are sorted using the given Closure to
determine order.
+ * <p>
+ * If the Closure has two parameters it is used like a traditional
Comparator on entries.
+ * Otherwise, the Closure is assumed to take a single entry parameter and
return a
+ * Comparable which is then used for further comparison.
+ *
+ * @param self the Map to check
+ * @param condition a Closure used as a comparator
+ * @return true if the map entries are sorted according to the closure
+ * @since 6.0.0
+ */
+ public static <K, V> boolean isSorted(Map<K, V> self,
@ClosureParams(value=FromString.class,
options={"Map.Entry<K,V>","Map.Entry<K,V>,Map.Entry<K,V>"}) Closure condition) {
+ Comparator<Map.Entry<K,V>> comparator =
(condition.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(condition) :
new ClosureComparator<>(condition);
+ return isSorted(self, comparator);
+ }
+
//--------------------------------------------------------------------------
// isUpperCase