Copilot commented on code in PR #2541:
URL: https://github.com/apache/groovy/pull/2541#discussion_r3262469494


##########
src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java:
##########
@@ -18459,6 +18461,293 @@ public void remove() {
         }
     }
 
+    
//--------------------------------------------------------------------------
+    // zipWithNext
+
+    /**
+     * Returns a list of all the successive adjacent pairs from this Iterable
+     * (a sliding window of size 2, step 1). The result has one fewer element
+     * than the input; an empty or single-element Iterable yields an empty 
list.
+     * Each pair is a {@link Tuple2}, which is also a {@code List}.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext() == [[1, 2], [2, 3], [3, 4]]
+     * assert [].zipWithNext() == []
+     * assert [42].zipWithNext() == []
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a list of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> List<Tuple2<T, T>> zipWithNext(Iterable<T> self) {
+        List<Tuple2<T, T>> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Applies the combiner to each successive adjacent pair from this 
Iterable,
+     * returning the list of results. The result has one fewer element than the
+     * input; an empty or single-element Iterable yields an empty list.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext{ a, b {@code ->} b - a } == [1, 1, 1]
+     * assert [3, 1, 4, 1, 5].zipWithNext{ a, b {@code ->} a {@code <=} b } == 
[false, true, false, true]
+     * assert 'abcd'.toList().zipWithNext{ a, b {@code ->} a + b } == ['ab', 
'bc', 'cd']
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param combiner a function applied to each adjacent pair
+     * @return a list of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> List<R> zipWithNext(Iterable<T> self, BiFunction<? 
super T, ? super T, ? extends R> combiner) {
+        List<R> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator(), combiner));
+        return result;
+    }
+
+    /**
+     * Returns a (lazy) iterator of all the successive adjacent pairs from 
this Iterator.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3].iterator().zipWithNext().toList() == [[1, 2], [2, 3]]
+     * </pre>
+     *
+     * @param self an Iterator
+     * @return an iterator of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> Iterator<Tuple2<T, T>> zipWithNext(Iterator<T> self) {
+        return new ZipWithNextIterator<>(self);
+    }
+
+    /**
+     * Returns a (lazy) iterator applying the combiner to each successive
+     * adjacent pair from this Iterator.
+     *
+     * @param self an Iterator
+     * @param combiner a function applied to each adjacent pair
+     * @return an iterator of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> Iterator<R> zipWithNext(Iterator<T> self, 
BiFunction<? super T, ? super T, ? extends R> combiner) {
+        Iterator<Tuple2<T, T>> pairs = new ZipWithNextIterator<>(self);
+        return new Iterator<R>() {
+            @Override
+            public boolean hasNext() {
+                return pairs.hasNext();
+            }
+
+            @Override
+            public R next() {
+                Tuple2<T, T> pair = pairs.next();
+                return combiner.apply(pair.getV1(), pair.getV2());
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private static final class ZipWithNextIterator<T> implements 
Iterator<Tuple2<T, T>> {
+        private final Iterator<T> delegate;
+        private T prev;
+        private boolean hasPrev;
+
+        private ZipWithNextIterator(Iterator<T> delegate) {
+            this.delegate = delegate;
+            if (delegate.hasNext()) {
+                prev = delegate.next();
+                hasPrev = true;
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            return hasPrev && delegate.hasNext();
+        }
+
+        @Override
+        public Tuple2<T, T> next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            T curr = delegate.next();
+            Tuple2<T, T> pair = new Tuple2<>(prev, curr);
+            prev = curr;
+            return pair;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    
//--------------------------------------------------------------------------
+    // groupConsecutive
+
+    /**
+     * Splits this Iterable into a list of sublists, each a maximal run of
+     * adjacent elements considered equal. Element order is preserved and the
+     * same value may appear in more than one run (unlike {@link 
#groupBy(Iterable, Closure)},
+     * which builds a map). Equality uses Groovy's number-aware coercion,
+     * consistent with {@link #unique(Collection)}.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 1, 2, 2, 2, 3, 1, 1].groupConsecutive() == [[1, 1], [2, 2, 
2], [3], [1, 1]]
+     * assert [1, 1L, 1.0, 2, 2].groupConsecutive() == [[1, 1L, 1.0], [2, 2]]
+     * assert [].groupConsecutive() == []
+     * assert [7].groupConsecutive() == [[7]]
+     * // run-length encoding; "dedupe consecutive" is just the run heads
+     * assert 'aaabbbcccd'.toList().groupConsecutive().collect{ run {@code ->} 
[run[0], run.size()] } == [['a', 3], ['b', 3], ['c', 3], ['d', 1]]
+     * assert 'aaabbbcccd'.toList().groupConsecutive()*.first().join() == 
'abcd'
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a list of the runs of adjacent equal elements
+     * @since 6.0.0
+     */
+    public static <T> List<List<T>> groupConsecutive(Iterable<T> self) {
+        List<List<T>> result = new ArrayList<>();
+        addAll(result, groupConsecutive(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Returns a (lazy) iterator over the runs of adjacent equal elements
+     * (number-aware coercion).
+     *
+     * @param self an Iterator
+     * @return an iterator over the runs of adjacent equal elements
+     * @since 6.0.0
+     */
+    public static <T> Iterator<List<T>> groupConsecutive(Iterator<T> self) {
+        return new GroupConsecutiveIterator<>(self, (a, b) -> coercedEquals(a, 
b));
+    }
+
+    /**
+     * Splits this Iterable into runs of adjacent elements whose key, as
+     * computed by the given function, is equal (number-aware coercion).
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert ['apple', 'avocado', 'banana', 'cherry', 'citrus', 
'date'].groupConsecutive{ it[0] } == [['apple', 'avocado'], ['banana'], 
['cherry', 'citrus'], ['date']]
+     * assert [1, 3, 5, 2, 4, 7, 9].groupConsecutive{ it % 2 } == [[1, 3, 5], 
[2, 4], [7, 9]]
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param keyFn extracts the grouping key for each element
+     * @return a list of the runs of adjacent key-equal elements
+     * @since 6.0.0
+     */
+    public static <T, K> List<List<T>> groupConsecutive(Iterable<T> self, 
Function<? super T, ? extends K> keyFn) {
+        List<List<T>> result = new ArrayList<>();
+        addAll(result, groupConsecutive(self.iterator(), keyFn));
+        return result;
+    }
+
+    /**
+     * Returns a (lazy) iterator over the runs of adjacent key-equal elements.
+     *
+     * @param self an Iterator
+     * @param keyFn extracts the grouping key for each element
+     * @return an iterator over the runs of adjacent key-equal elements
+     * @since 6.0.0
+     */
+    public static <T, K> Iterator<List<T>> groupConsecutive(Iterator<T> self, 
Function<? super T, ? extends K> keyFn) {
+        return new GroupConsecutiveIterator<>(self, (a, b) -> 
coercedEquals(keyFn.apply(a), keyFn.apply(b)));

Review Comment:
   groupConsecutive(Iterator, Function) calls keyFn.apply on the previous 
element again for every comparison, so keys for elements in the middle of a run 
are computed multiple times. If keyFn is expensive or has side effects this can 
impact performance and (with side effects) grouping behavior; consider 
computing and carrying the current key alongside the current element so each 
element’s key is evaluated once.
   



##########
src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java:
##########
@@ -18459,6 +18461,293 @@ public void remove() {
         }
     }
 
+    
//--------------------------------------------------------------------------
+    // zipWithNext
+
+    /**
+     * Returns a list of all the successive adjacent pairs from this Iterable
+     * (a sliding window of size 2, step 1). The result has one fewer element
+     * than the input; an empty or single-element Iterable yields an empty 
list.
+     * Each pair is a {@link Tuple2}, which is also a {@code List}.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext() == [[1, 2], [2, 3], [3, 4]]
+     * assert [].zipWithNext() == []
+     * assert [42].zipWithNext() == []
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a list of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> List<Tuple2<T, T>> zipWithNext(Iterable<T> self) {
+        List<Tuple2<T, T>> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Applies the combiner to each successive adjacent pair from this 
Iterable,
+     * returning the list of results. The result has one fewer element than the
+     * input; an empty or single-element Iterable yields an empty list.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext{ a, b {@code ->} b - a } == [1, 1, 1]
+     * assert [3, 1, 4, 1, 5].zipWithNext{ a, b {@code ->} a {@code <=} b } == 
[false, true, false, true]
+     * assert 'abcd'.toList().zipWithNext{ a, b {@code ->} a + b } == ['ab', 
'bc', 'cd']
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param combiner a function applied to each adjacent pair
+     * @return a list of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> List<R> zipWithNext(Iterable<T> self, BiFunction<? 
super T, ? super T, ? extends R> combiner) {
+        List<R> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator(), combiner));
+        return result;
+    }
+
+    /**
+     * Returns a (lazy) iterator of all the successive adjacent pairs from 
this Iterator.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3].iterator().zipWithNext().toList() == [[1, 2], [2, 3]]
+     * </pre>
+     *
+     * @param self an Iterator
+     * @return an iterator of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> Iterator<Tuple2<T, T>> zipWithNext(Iterator<T> self) {
+        return new ZipWithNextIterator<>(self);
+    }
+
+    /**
+     * Returns a (lazy) iterator applying the combiner to each successive
+     * adjacent pair from this Iterator.
+     *
+     * @param self an Iterator
+     * @param combiner a function applied to each adjacent pair
+     * @return an iterator of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> Iterator<R> zipWithNext(Iterator<T> self, 
BiFunction<? super T, ? super T, ? extends R> combiner) {
+        Iterator<Tuple2<T, T>> pairs = new ZipWithNextIterator<>(self);
+        return new Iterator<R>() {
+            @Override
+            public boolean hasNext() {
+                return pairs.hasNext();
+            }
+
+            @Override
+            public R next() {
+                Tuple2<T, T> pair = pairs.next();
+                return combiner.apply(pair.getV1(), pair.getV2());
+            }

Review Comment:
   zipWithNext(Iterator, BiFunction) currently allocates a Tuple2 for every 
adjacent pair and then immediately discards it after applying the combiner. 
This adds avoidable allocation/GC overhead for large iterators; consider 
implementing a dedicated iterator that keeps the previous element and applies 
the combiner directly without creating intermediate Tuple2 objects.



##########
src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java:
##########
@@ -18459,6 +18461,293 @@ public void remove() {
         }
     }
 
+    
//--------------------------------------------------------------------------
+    // zipWithNext
+
+    /**
+     * Returns a list of all the successive adjacent pairs from this Iterable
+     * (a sliding window of size 2, step 1). The result has one fewer element
+     * than the input; an empty or single-element Iterable yields an empty 
list.
+     * Each pair is a {@link Tuple2}, which is also a {@code List}.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext() == [[1, 2], [2, 3], [3, 4]]
+     * assert [].zipWithNext() == []
+     * assert [42].zipWithNext() == []
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a list of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> List<Tuple2<T, T>> zipWithNext(Iterable<T> self) {
+        List<Tuple2<T, T>> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Applies the combiner to each successive adjacent pair from this 
Iterable,
+     * returning the list of results. The result has one fewer element than the
+     * input; an empty or single-element Iterable yields an empty list.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext{ a, b {@code ->} b - a } == [1, 1, 1]
+     * assert [3, 1, 4, 1, 5].zipWithNext{ a, b {@code ->} a {@code <=} b } == 
[false, true, false, true]
+     * assert 'abcd'.toList().zipWithNext{ a, b {@code ->} a + b } == ['ab', 
'bc', 'cd']
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param combiner a function applied to each adjacent pair
+     * @return a list of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> List<R> zipWithNext(Iterable<T> self, BiFunction<? 
super T, ? super T, ? extends R> combiner) {
+        List<R> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator(), combiner));
+        return result;
+    }

Review Comment:
   These new zipWithNext methods introduce new GDK behavior but there are no 
accompanying unit tests in this PR. Please add tests covering empty/singleton 
inputs, typical multi-element cases, and the BiFunction combiner overload 
(including Iterator-based lazy usage).



##########
src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java:
##########
@@ -18459,6 +18461,293 @@ public void remove() {
         }
     }
 
+    
//--------------------------------------------------------------------------
+    // zipWithNext
+
+    /**
+     * Returns a list of all the successive adjacent pairs from this Iterable
+     * (a sliding window of size 2, step 1). The result has one fewer element
+     * than the input; an empty or single-element Iterable yields an empty 
list.
+     * Each pair is a {@link Tuple2}, which is also a {@code List}.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext() == [[1, 2], [2, 3], [3, 4]]
+     * assert [].zipWithNext() == []
+     * assert [42].zipWithNext() == []
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a list of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> List<Tuple2<T, T>> zipWithNext(Iterable<T> self) {
+        List<Tuple2<T, T>> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Applies the combiner to each successive adjacent pair from this 
Iterable,
+     * returning the list of results. The result has one fewer element than the
+     * input; an empty or single-element Iterable yields an empty list.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3, 4].zipWithNext{ a, b {@code ->} b - a } == [1, 1, 1]
+     * assert [3, 1, 4, 1, 5].zipWithNext{ a, b {@code ->} a {@code <=} b } == 
[false, true, false, true]
+     * assert 'abcd'.toList().zipWithNext{ a, b {@code ->} a + b } == ['ab', 
'bc', 'cd']
+     * </pre>
+     *
+     * @param self an Iterable
+     * @param combiner a function applied to each adjacent pair
+     * @return a list of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> List<R> zipWithNext(Iterable<T> self, BiFunction<? 
super T, ? super T, ? extends R> combiner) {
+        List<R> result = new ArrayList<>();
+        addAll(result, zipWithNext(self.iterator(), combiner));
+        return result;
+    }
+
+    /**
+     * Returns a (lazy) iterator of all the successive adjacent pairs from 
this Iterator.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 2, 3].iterator().zipWithNext().toList() == [[1, 2], [2, 3]]
+     * </pre>
+     *
+     * @param self an Iterator
+     * @return an iterator of the adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T> Iterator<Tuple2<T, T>> zipWithNext(Iterator<T> self) {
+        return new ZipWithNextIterator<>(self);
+    }
+
+    /**
+     * Returns a (lazy) iterator applying the combiner to each successive
+     * adjacent pair from this Iterator.
+     *
+     * @param self an Iterator
+     * @param combiner a function applied to each adjacent pair
+     * @return an iterator of the combined adjacent pairs
+     * @since 6.0.0
+     */
+    public static <T, R> Iterator<R> zipWithNext(Iterator<T> self, 
BiFunction<? super T, ? super T, ? extends R> combiner) {
+        Iterator<Tuple2<T, T>> pairs = new ZipWithNextIterator<>(self);
+        return new Iterator<R>() {
+            @Override
+            public boolean hasNext() {
+                return pairs.hasNext();
+            }
+
+            @Override
+            public R next() {
+                Tuple2<T, T> pair = pairs.next();
+                return combiner.apply(pair.getV1(), pair.getV2());
+            }
+
+            @Override
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+
+    private static final class ZipWithNextIterator<T> implements 
Iterator<Tuple2<T, T>> {
+        private final Iterator<T> delegate;
+        private T prev;
+        private boolean hasPrev;
+
+        private ZipWithNextIterator(Iterator<T> delegate) {
+            this.delegate = delegate;
+            if (delegate.hasNext()) {
+                prev = delegate.next();
+                hasPrev = true;
+            }
+        }
+
+        @Override
+        public boolean hasNext() {
+            return hasPrev && delegate.hasNext();
+        }
+
+        @Override
+        public Tuple2<T, T> next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            T curr = delegate.next();
+            Tuple2<T, T> pair = new Tuple2<>(prev, curr);
+            prev = curr;
+            return pair;
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    
//--------------------------------------------------------------------------
+    // groupConsecutive
+
+    /**
+     * Splits this Iterable into a list of sublists, each a maximal run of
+     * adjacent elements considered equal. Element order is preserved and the
+     * same value may appear in more than one run (unlike {@link 
#groupBy(Iterable, Closure)},
+     * which builds a map). Equality uses Groovy's number-aware coercion,
+     * consistent with {@link #unique(Collection)}.
+     * <p>
+     * Example:
+     * <pre class="language-groovy groovyTestCase">
+     * assert [1, 1, 2, 2, 2, 3, 1, 1].groupConsecutive() == [[1, 1], [2, 2, 
2], [3], [1, 1]]
+     * assert [1, 1L, 1.0, 2, 2].groupConsecutive() == [[1, 1L, 1.0], [2, 2]]
+     * assert [].groupConsecutive() == []
+     * assert [7].groupConsecutive() == [[7]]
+     * // run-length encoding; "dedupe consecutive" is just the run heads
+     * assert 'aaabbbcccd'.toList().groupConsecutive().collect{ run {@code ->} 
[run[0], run.size()] } == [['a', 3], ['b', 3], ['c', 3], ['d', 1]]
+     * assert 'aaabbbcccd'.toList().groupConsecutive()*.first().join() == 
'abcd'
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a list of the runs of adjacent equal elements
+     * @since 6.0.0
+     */
+    public static <T> List<List<T>> groupConsecutive(Iterable<T> self) {
+        List<List<T>> result = new ArrayList<>();
+        addAll(result, groupConsecutive(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Returns a (lazy) iterator over the runs of adjacent equal elements
+     * (number-aware coercion).
+     *
+     * @param self an Iterator
+     * @return an iterator over the runs of adjacent equal elements
+     * @since 6.0.0
+     */
+    public static <T> Iterator<List<T>> groupConsecutive(Iterator<T> self) {
+        return new GroupConsecutiveIterator<>(self, (a, b) -> coercedEquals(a, 
b));
+    }

Review Comment:
   These new groupConsecutive overloads add new core collection semantics 
(including Groovy’s number-aware equality and BiPredicate customization) but 
there are no accompanying unit tests in this PR. Please add tests for default 
number coercion (e.g. 1, 1L, 1.0), keyFn grouping, custom sameRun predicate, 
and iterator-based behavior.



##########
src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java:
##########
@@ -11141,6 +11143,103 @@ public static Iterator<Tuple2<Long, Long>> 
zipping(long[] self, long[] other) {
         return DefaultGroovyMethods.zip(new LongArrayIterator(self), new 
LongArrayIterator(other));
     }
 
+    
//--------------------------------------------------------------------------
+    // groupConsecutive
+
+    /**
+     * Splits this array into a list of sublists, each a maximal run of
+     * adjacent elements considered equal (number-aware coercion).
+     * <pre class="language-groovy groovyTestCase">
+     * Integer[] nums = [1, 1, 2, 2, 2, 3, 1, 1]
+     * assert nums.groupConsecutive() == [[1, 1], [2, 2, 2], [3], [1, 1]]
+     * </pre>
+     *
+     * @param self an array
+     * @return a list of the runs of adjacent equal elements
+     * @see DefaultGroovyMethods#groupConsecutive(Iterable)
+     * @since 6.0.0
+     */
+    public static <T> List<List<T>> groupConsecutive(T[] self) {
+        return DefaultGroovyMethods.groupConsecutive(new 
ArrayIterable<>(self));
+    }
+
+    /**
+     * Splits this array into runs of adjacent elements whose key, as computed
+     * by the given function, is equal (number-aware coercion).
+     * <pre class="language-groovy groovyTestCase">
+     * String[] fruit = ['apple', 'avocado', 'banana', 'cherry', 'citrus', 
'date']
+     * assert fruit.groupConsecutive{ it[0] } == [['apple', 'avocado'], 
['banana'], ['cherry', 'citrus'], ['date']]
+     * </pre>
+     *
+     * @param self an array
+     * @param keyFn extracts the grouping key for each element
+     * @return a list of the runs of adjacent key-equal elements
+     * @see DefaultGroovyMethods#groupConsecutive(Iterable, 
java.util.function.Function)
+     * @since 6.0.0
+     */
+    public static <T, K> List<List<T>> groupConsecutive(T[] self, Function<? 
super T, ? extends K> keyFn) {
+        return DefaultGroovyMethods.groupConsecutive(new 
ArrayIterable<>(self), keyFn);
+    }
+
+    /**
+     * Splits this array into runs where the given predicate, applied to the
+     * current run's previous element and the next element, holds. Use this to
+     * opt out of the default number-aware equality.
+     * <pre class="language-groovy groovyTestCase">
+     * Number[] ns = [1, 1L, 1.0, 2, 2]
+     * assert ns.groupConsecutive{ a, b {@code ->} a.equals(b) } == [[1], 
[1L], [1.0], [2, 2]]
+     * </pre>
+     *
+     * @param self an array
+     * @param sameRun tests whether the next element continues the current run
+     * @return a list of the runs
+     * @see DefaultGroovyMethods#groupConsecutive(Iterable, 
java.util.function.BiPredicate)
+     * @since 6.0.0
+     */
+    public static <T> List<List<T>> groupConsecutive(T[] self, BiPredicate<? 
super T, ? super T> sameRun) {
+        return DefaultGroovyMethods.groupConsecutive(new 
ArrayIterable<>(self), sameRun);
+    }

Review Comment:
   ArrayGroovyMethods adds new groupConsecutive array overloads but this PR 
doesn’t include corresponding tests. Please add tests (and, if relevant, 
STC/CompileStatic coverage) to ensure T[] array calls behave the same as the 
Iterable-based DefaultGroovyMethods variants.



##########
src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java:
##########
@@ -11141,6 +11143,103 @@ public static Iterator<Tuple2<Long, Long>> 
zipping(long[] self, long[] other) {
         return DefaultGroovyMethods.zip(new LongArrayIterator(self), new 
LongArrayIterator(other));
     }
 
+    
//--------------------------------------------------------------------------
+    // groupConsecutive
+
+    /**
+     * Splits this array into a list of sublists, each a maximal run of
+     * adjacent elements considered equal (number-aware coercion).
+     * <pre class="language-groovy groovyTestCase">
+     * Integer[] nums = [1, 1, 2, 2, 2, 3, 1, 1]
+     * assert nums.groupConsecutive() == [[1, 1], [2, 2, 2], [3], [1, 1]]
+     * </pre>
+     *
+     * @param self an array
+     * @return a list of the runs of adjacent equal elements
+     * @see DefaultGroovyMethods#groupConsecutive(Iterable)
+     * @since 6.0.0
+     */
+    public static <T> List<List<T>> groupConsecutive(T[] self) {
+        return DefaultGroovyMethods.groupConsecutive(new 
ArrayIterable<>(self));
+    }
+
+    /**
+     * Splits this array into runs of adjacent elements whose key, as computed
+     * by the given function, is equal (number-aware coercion).
+     * <pre class="language-groovy groovyTestCase">
+     * String[] fruit = ['apple', 'avocado', 'banana', 'cherry', 'citrus', 
'date']
+     * assert fruit.groupConsecutive{ it[0] } == [['apple', 'avocado'], 
['banana'], ['cherry', 'citrus'], ['date']]
+     * </pre>
+     *
+     * @param self an array
+     * @param keyFn extracts the grouping key for each element
+     * @return a list of the runs of adjacent key-equal elements
+     * @see DefaultGroovyMethods#groupConsecutive(Iterable, 
java.util.function.Function)
+     * @since 6.0.0
+     */
+    public static <T, K> List<List<T>> groupConsecutive(T[] self, Function<? 
super T, ? extends K> keyFn) {
+        return DefaultGroovyMethods.groupConsecutive(new 
ArrayIterable<>(self), keyFn);
+    }
+
+    /**
+     * Splits this array into runs where the given predicate, applied to the
+     * current run's previous element and the next element, holds. Use this to
+     * opt out of the default number-aware equality.
+     * <pre class="language-groovy groovyTestCase">
+     * Number[] ns = [1, 1L, 1.0, 2, 2]
+     * assert ns.groupConsecutive{ a, b {@code ->} a.equals(b) } == [[1], 
[1L], [1.0], [2, 2]]
+     * </pre>
+     *
+     * @param self an array
+     * @param sameRun tests whether the next element continues the current run
+     * @return a list of the runs
+     * @see DefaultGroovyMethods#groupConsecutive(Iterable, 
java.util.function.BiPredicate)
+     * @since 6.0.0
+     */
+    public static <T> List<List<T>> groupConsecutive(T[] self, BiPredicate<? 
super T, ? super T> sameRun) {
+        return DefaultGroovyMethods.groupConsecutive(new 
ArrayIterable<>(self), sameRun);
+    }
+
+    
//--------------------------------------------------------------------------
+    // zipWithNext
+
+    /**
+     * Returns a list of all the successive adjacent pairs from this array
+     * (a sliding window of size 2, step 1).
+     * <pre class="language-groovy groovyTestCase">
+     * Integer[] nums = [1, 2, 3, 4]
+     * assert nums.zipWithNext() == [[1, 2], [2, 3], [3, 4]]
+     * </pre>
+     *
+     * @param self an array
+     * @return a list of the adjacent pairs
+     * @see DefaultGroovyMethods#zipWithNext(Iterable)
+     * @since 6.0.0
+     */
+    public static <T> List<Tuple2<T, T>> zipWithNext(T[] self) {
+        return DefaultGroovyMethods.zipWithNext(new ArrayIterable<>(self));
+    }
+
+    /**
+     * Applies the combiner to each successive adjacent pair from this array,
+     * returning the list of results.
+     * <pre class="language-groovy groovyTestCase">
+     * Integer[] nums = [1, 2, 3, 4]
+     * assert nums.zipWithNext{ a, b {@code ->} b - a } == [1, 1, 1]
+     * String[] letters = ['a', 'b', 'c', 'd']
+     * assert letters.zipWithNext{ a, b {@code ->} a + b } == ['ab', 'bc', 
'cd']
+     * </pre>
+     *
+     * @param self an array
+     * @param combiner a function applied to each adjacent pair
+     * @return a list of the combined adjacent pairs
+     * @see DefaultGroovyMethods#zipWithNext(Iterable, 
java.util.function.BiFunction)
+     * @since 6.0.0
+     */
+    public static <T, R> List<R> zipWithNext(T[] self, BiFunction<? super T, ? 
super T, ? extends R> combiner) {
+        return DefaultGroovyMethods.zipWithNext(new ArrayIterable<>(self), 
combiner);
+    }

Review Comment:
   ArrayGroovyMethods adds new zipWithNext array overloads but this PR doesn’t 
include corresponding tests. Please add tests for the pair-producing and 
combiner overloads (including empty/singleton arrays) to guard the new API.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to