Paul King created GROOVY-12016:
----------------------------------
Summary: New GDK methods: zipWithNext and groupConsecutive
Key: GROOVY-12016
URL: https://issues.apache.org/jira/browse/GROOVY-12016
Project: Groovy
Issue Type: New Feature
Components: Extension methods
Reporter: Paul King
Assignee: Paul King
h2. {{zipWithNext}}
Add a {{zipWithNext}} GDK method returning successive adjacent pairs
(a sliding window of size 2, step 1), plus an overload taking a
combiner. Mirrors Kotlin's {{zipWithNext()}} / {{zipWithNext(transform)}}.
Today this needs the non-obvious, off-by-one-prone {{collate(2, 1, false)}}.
h3. Proposed signatures
{code:java}
List<Tuple2<T,T>> zipWithNext(Iterable<T> self)
<R> List<R> zipWithNext(Iterable<T> self, BiFunction<? super T,?
super T,? extends R> combiner)
Iterator<Tuple2<T,T>> zipWithNext(Iterator<T> self) // lazy
<R> Iterator<R> zipWithNext(Iterator<T> self, BiFunction<? super T,?
super T,? extends R> combiner)
List<Tuple2<T,T>> zipWithNext(T[] self)
<R> List<R> zipWithNext(T[] self, BiFunction<? super T,? super T,?
extends R> combiner)
{code}
h3. Examples
{code:groovy}
[1, 2, 3, 4].zipWithNext() == [new Tuple2(1,2), new Tuple2(2,3), new
Tuple2(3,4)]
[1, 2, 3, 4].zipWithNext{ a,b -> b-a } == [1, 1, 1] // pairwise
deltas
[3,1,4,1,5].zipWithNext{ a,b -> a<=b }.every() == false // monotonic
check
[].zipWithNext() == []
[42].zipWithNext() == [] // no adjacent
pair
{code}
h3. Notes
Groovy closures coerce to {{BiFunction}}. Primitive-array overloads
deferred (Tuple2 boxes anyway).
h2. {{groupConsecutive}}
Add a {{groupConsecutive}} GDK method splitting a sequence into maximal
runs of adjacent "same" elements (order preserved; the same key may
recur in separate runs). Unlike {{groupBy}} (a {{Map}}, global, loses
order and run boundaries) there is no native equivalent today.
h3. Proposed signatures
{code:java}
List<List<T>> groupConsecutive(Iterable<T> self)
// default equality
<K> List<List<T>> groupConsecutive(Iterable<T> self, Function<? super T,?
extends K> keyFn) // by derived key
List<List<T>> groupConsecutive(Iterable<T> self, BiPredicate<? super T,?
super T> sameRun)
// + Iterator (lazy) and T[] receiver rows, same trio
{code}
h3. Examples
{code:groovy}
[1,1,2,2,2,3,1,1].groupConsecutive() == [[1,1],[2,2,2],[3],[1,1]] //
two separate [1,1] runs
[1,1L,1.0,2,2].groupConsecutive() == [[1,1L,1.0],[2,2]] //
number-aware default
['apple','avocado','banana'].groupConsecutive{ it[0] } ==
[['apple','avocado'],['banana']]
xs.groupConsecutive{ a,b -> Objects.equals(a,b) } //
opt out to strict .equals()
'aaabbbcccd'.toList().groupConsecutive().collect{ [it[0], it.size()] } //
run-length encoding
{code}
h3. Design notes
* No-arg uses Groovy's number-aware equality ({{coercedEquals}}),
consistent with {{unique()}} and the set-algebra family (derived from
the DefaultGroovyMethods source; {{contains}}'s plain-equals is the
documented anomaly, not the model).
* Opt out via the {{BiPredicate}} overload: {{Objects.equals}} for
strict, {{(a <=> b) == 0}} for natural-order/value equivalence,
{{cmp.compare(a,b)==0}} for a Comparator. A {{Comparator}} overload was
rejected: a boolean closure silently mis-coerces to it.
* Arity-disambiguated overloads (0/1/2 params); no closure-arity sniffing.
* {{dedupeConsecutive}} intentionally NOT included — it is
{{groupConsecutive()*.first()}} (cf. {{findAll}} with no {{rejectAll}}).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)