@@ -9657,6 +9657,176 @@ public static boolean isNotCase(Map<?, ?> caseValue, Object switchValue) {
96579657 return !isCase(caseValue, switchValue);
96589658 }
96599659
9660+ //--------------------------------------------------------------------------
9661+ // isSorted
9662+
9663+ /**
9664+ * Determines if the Iterable is sorted. Assumes the elements are
9665+ * comparable and uses a {@link NumberAwareComparator} to determine the order.
9666+ * <pre class="groovyTestCase">
9667+ * assert [1, 2, 3].isSorted()
9668+ * assert !([3, 1, 2].isSorted())
9669+ * assert [].isSorted()
9670+ * </pre>
9671+ *
9672+ * @param self the Iterable to check
9673+ * @return true if the elements are sorted in non-descending order
9674+ * @see #isSorted(Iterable, Comparator)
9675+ * @since 6.0.0
9676+ */
9677+ public static <T> boolean isSorted(Iterable<T> self) {
9678+ return isSorted(self, new NumberAwareComparator<>());
9679+ }
9680+
9681+ /**
9682+ * Determines if the Iterable is sorted according to the given Comparator.
9683+ * This is efficient — it checks adjacent pairs in a single pass and
9684+ * short-circuits on the first out-of-order pair.
9685+ * {@code SortedSet} instances always return {@code true}.
9686+ * <pre class="groovyTestCase">
9687+ * assert ["hello","Hey","hi"].isSorted(String.CASE_INSENSITIVE_ORDER)
9688+ * assert !(["hi","Hey","hello"].isSorted(String.CASE_INSENSITIVE_ORDER))
9689+ * assert (new TreeSet(["c","a","b"])).isSorted()
9690+ * </pre>
9691+ *
9692+ * @param self the Iterable to check
9693+ * @param comparator a Comparator used for the comparison
9694+ * @return true if the elements are sorted according to the comparator
9695+ * @since 6.0.0
9696+ */
9697+ public static <T> boolean isSorted(Iterable<T> self, Comparator<? super T> comparator) {
9698+ if (self instanceof SortedSet) return true;
9699+ return isSorted(self.iterator(), comparator);
9700+ }
9701+
9702+ /**
9703+ * Determines if the Iterable is sorted using the given Closure to determine order.
9704+ * <p>
9705+ * If the Closure has two parameters it is used like a traditional Comparator.
9706+ * Otherwise, the Closure is assumed to take a single parameter and return a
9707+ * Comparable (typically an Integer) which is then used for further comparison.
9708+ * <pre class="groovyTestCase">
9709+ * assert ["hi","hey","hello"].isSorted { it.length() }
9710+ * assert !["hello","hi","hey"].isSorted { it.length() }
9711+ * assert ["hi","hey","hello"].isSorted { a, b {@code ->} a.length() {@code <=>} b.length() }
9712+ * </pre>
9713+ *
9714+ * @param self the Iterable to check
9715+ * @param closure a 1 or 2 arg Closure used to determine the ordering
9716+ * @return true if the elements are sorted according to the closure
9717+ * @see #isSorted(Iterable, Comparator)
9718+ * @since 6.0.0
9719+ */
9720+ public static <T> boolean isSorted(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
9721+ Comparator<T> comparator = (closure.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(closure) : new ClosureComparator<>(closure);
9722+ return isSorted(self, comparator);
9723+ }
9724+
9725+ /**
9726+ * Determines if the Iterator elements are sorted. Assumes the elements are
9727+ * comparable and uses a {@link NumberAwareComparator} to determine the order.
9728+ * <p>
9729+ * The iterator will be exhausted of elements after determining the sorted status.
9730+ *
9731+ * @param self the Iterator to check
9732+ * @return true if the elements are sorted in non-descending order
9733+ * @see #isSorted(Iterator, Comparator)
9734+ * @since 6.0.0
9735+ */
9736+ public static <T> boolean isSorted(Iterator<T> self) {
9737+ return isSorted(self, new NumberAwareComparator<>());
9738+ }
9739+
9740+ /**
9741+ * Determines if the Iterator elements are sorted according to the given Comparator.
9742+ * This is efficient — it checks adjacent pairs and short-circuits on the first
9743+ * out-of-order pair. The iterator will be exhausted only if the elements are sorted.
9744+ *
9745+ * @param self the Iterator to check
9746+ * @param comparator a Comparator used for the comparison
9747+ * @return true if the elements are sorted according to the comparator
9748+ * @since 6.0.0
9749+ */
9750+ public static <T> boolean isSorted(Iterator<T> self, Comparator<? super T> comparator) {
9751+ if (!self.hasNext()) return true;
9752+ T prev = self.next();
9753+ while (self.hasNext()) {
9754+ T curr = self.next();
9755+ if (comparator.compare(prev, curr) > 0) return false;
9756+ prev = curr;
9757+ }
9758+ return true;
9759+ }
9760+
9761+ /**
9762+ * Determines if the Iterator elements are sorted using the given Closure to determine order.
9763+ * <p>
9764+ * If the Closure has two parameters it is used like a traditional Comparator.
9765+ * Otherwise, the Closure is assumed to take a single parameter and return a
9766+ * Comparable which is then used for further comparison.
9767+ * <p>
9768+ * The iterator will be exhausted of elements after determining the sorted status.
9769+ *
9770+ * @param self the Iterator to check
9771+ * @param closure a 1 or 2 arg Closure used to determine the ordering
9772+ * @return true if the elements are sorted according to the closure
9773+ * @see #isSorted(Iterator, Comparator)
9774+ * @since 6.0.0
9775+ */
9776+ public static <T> boolean isSorted(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
9777+ Comparator<T> comparator = (closure.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(closure) : new ClosureComparator<>(closure);
9778+ return isSorted(self, comparator);
9779+ }
9780+
9781+ /**
9782+ * Determines if the Map entries are sorted.
9783+ * Assumes the entries are comparable and uses a {@link NumberAwareValueComparator}
9784+ * to determine the order. The map's iteration order is checked.
9785+ * <pre class="groovyTestCase">
9786+ * def map = new LinkedHashMap([b:3, d:4, a:5, c:6])
9787+ * assert map.isSorted()
9788+ * </pre>
9789+ *
9790+ * @param self the Map to check
9791+ * @return true if the map entries are sorted in non-descending order
9792+ * @since 6.0.0
9793+ */
9794+ public static <K, V> boolean isSorted(Map<K, V> self) {
9795+ return isSorted(self, new NumberAwareValueComparator<>());
9796+ }
9797+
9798+ /**
9799+ * Determines if the Map entries are sorted according to the given Comparator.
9800+ * The map's iteration order is checked.
9801+ * {@code SortedMap} instances always return {@code true}.
9802+ *
9803+ * @param self the Map to check
9804+ * @param comparator a Comparator used to compare Map.Entry instances
9805+ * @return true if the map entries are sorted according to the comparator
9806+ * @since 6.0.0
9807+ */
9808+ public static <K, V> boolean isSorted(Map<K, V> self, Comparator<Map.Entry<K, V>> comparator) {
9809+ if (self instanceof SortedMap) return true;
9810+ return isSorted(self.entrySet(), comparator);
9811+ }
9812+
9813+ /**
9814+ * Determines if the Map entries are sorted using the given Closure to determine order.
9815+ * <p>
9816+ * If the Closure has two parameters it is used like a traditional Comparator on entries.
9817+ * Otherwise, the Closure is assumed to take a single entry parameter and return a
9818+ * Comparable which is then used for further comparison.
9819+ *
9820+ * @param self the Map to check
9821+ * @param condition a Closure used as a comparator
9822+ * @return true if the map entries are sorted according to the closure
9823+ * @since 6.0.0
9824+ */
9825+ 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) {
9826+ Comparator<Map.Entry<K,V>> comparator = (condition.getMaximumNumberOfParameters() == 1) ? new OrderBy<>(condition) : new ClosureComparator<>(condition);
9827+ return isSorted(self, comparator);
9828+ }
9829+
96609830 //--------------------------------------------------------------------------
96619831 // isUpperCase
96629832
0 commit comments