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 bd15e7c8c8 GROOVY-11808: create a DGM#groupByMany extension method 
(minor refactor)
bd15e7c8c8 is described below

commit bd15e7c8c829f499de547569d3222a31bf016c6e
Author: Paul King <[email protected]>
AuthorDate: Mon Dec 1 16:50:04 2025 +1000

    GROOVY-11808: create a DGM#groupByMany extension method (minor refactor)
---
 .../groovy/runtime/ArrayGroovyMethods.java         | 33 ++++++++++++++++
 .../groovy/runtime/DefaultGroovyMethods.java       | 46 +++++++++++-----------
 2 files changed, 56 insertions(+), 23 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java 
b/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
index 3a6d992d00..8185baddc6 100644
--- a/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/ArrayGroovyMethods.java
@@ -4378,6 +4378,39 @@ public class ArrayGroovyMethods extends 
DefaultGroovyMethodsSupport {
         return DefaultGroovyMethods.groupBy(new ArrayIterable<>(self), 
closures);
     }
 
+    
//--------------------------------------------------------------------------
+    // groupByMany
+
+    /**
+     * Groups all array members into (sub)groups determined by the supplied 
key mapping closure.
+     * The closure should return a list of keys applicable to a member.
+     * The member will be grouped under each key from the list.
+     *
+     * Example usage finding the words with capital letters:
+     * <pre class="groovyTestCase">
+     * String[] words = ['TO', 'be', 'Or', 'nOT', 'To', 'be']
+     * assert words.groupByMany(w -&gt; w.toSet().grep(~'[A-Z]')) == [T:['TO', 
'nOT', 'To'], O:['TO', 'Or', 'nOT']]
+     * </pre>
+     *
+     * If the lists of generated keys are all of size 1, the result will be 
the same as
+     * {@code groupBy} with a closure returning the value in the key list:
+     * <pre class="groovyTestCase">
+     * String[] animals = ['cat', 'dog', 'bird', 'pony']
+     * assert animals.groupByMany(a -&gt; [a.size()]) == 
animals.groupBy(String::size)
+     * </pre>
+     *
+     * @param self  an array to group
+     * @param keyFn a closure returning an Iterable of keys for each element
+     * @return a new Map from keys to lists of elements
+     * @since 6.0.0
+     */
+    public static <T, K> Map<K, List<T>> groupByMany(
+        T[] self,
+        @ClosureParams(FirstParam.Component.class) Closure<? extends 
Iterable<? extends K>> keyFn
+    ) {
+        return DefaultGroovyMethods.groupByMany(Arrays.asList(self), keyFn);
+    }
+
     
//--------------------------------------------------------------------------
     // head
 
diff --git 
a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java 
b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 77206f1049..f30efb8d5b 100644
--- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -7987,14 +7987,12 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
     // groupByMany
 
     /**
-     * Sorts all Iterable members into (sub)groups determined by the supplied
-     * mapping closure. Each closure should return a list of keys. The item
-     * should be grouped by each of these keys. The returned LinkedHashMap 
will have
-     * an entry for each distinct 'key path' returned from the closures, with 
each value
-     * being a list of items for that 'group path'.
+     * Groups all items from the iterable into (sub)groups determined by the 
supplied key mapping closure.
+     * The closure should return a list of keys applicable to an item.
+     * The item will be grouped under each key from the list.
      *
      * Example usage:
-     * <pre>
+     * <pre class="groovyTestCase">
      * def people = [
      *     [name: 'Alice', cities: ['NY', 'LA']],
      *     [name: 'Bob',   cities: ['NY']],
@@ -8015,7 +8013,10 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
      * @return a new Map from keys to lists of elements
      * @since 6.0.0
      */
-    public static <T, K> Map<K, List<T>> groupByMany(Iterable<T> self, 
Closure<? extends Iterable<? extends K>> keyFn) {
+    public static <T, K> Map<K, List<T>> groupByMany(
+        Iterable<T> self,
+        @ClosureParams(FirstParam.FirstGenericType.class) Closure<? extends 
Iterable<? extends K>> keyFn
+    ) {
         Map<K, List<T>> result = new HashMap<>();
 
         for (T item : self) {
@@ -8032,14 +8033,12 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Sorts all Iterable members into (sub)groups determined by the supplied
-     * mapping closure. Each closure should return a list of keys. The item
-     * should be grouped by each of these keys. The returned LinkedHashMap 
will have
-     * an entry for each distinct 'key path' returned from the closures, with 
each value
-     * being a list of items for that 'group path'.
+     * Groups all elements from the iterable into (sub)groups determined by 
the supplied key mapping closure.
+     * The key mapping closure should return a list of keys applicable to an 
element.
+     * The value returned by mapping the element with the value mapping 
closure will be grouped under each key from the list.
      *
      * Example usage:
-     * <pre>
+     * <pre class="groovyTestCase">
      * record Person(String name, List&lt;String> cities) { }
      *
      * def people = [
@@ -8063,8 +8062,12 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
      * @return a new Map from keys to lists of elements
      * @since 6.0.0
      */
-    public static <T, K> Map<K, List<T>> groupByMany(Iterable<T> self, 
Closure<? extends T> valueFn, Closure<? extends Iterable<? extends K>> keyFn) {
-        Map<K, List<T>> result = new HashMap<>();
+    public static <T, U, K> Map<K, List<U>> groupByMany(
+        Iterable<T> self,
+        @ClosureParams(FirstParam.FirstGenericType.class) Closure<? extends U> 
valueFn,
+        @ClosureParams(FirstParam.FirstGenericType.class) Closure<? extends 
Iterable<? extends K>> keyFn
+    ) {
+        Map<K, List<U>> result = new HashMap<>();
 
         for (T item : self) {
             Iterable<? extends K> keys = keyFn.call(item);
@@ -8080,14 +8083,11 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Sorts all Iterable members into (sub)groups determined by the supplied
-     * mapping closure. Each closure should return a list of keys. The item
-     * should be grouped by each of these keys. The returned LinkedHashMap 
will have
-     * an entry for each distinct 'key path' returned from the closures, with 
each value
-     * being a list of items for that 'group path'.
+     * Groups all keys from the map into (sub)groups determined by the values.
+     * Each key will be grouped under each item in the value list.
      *
      * Example usage:
-     * <pre>
+     * <pre class="groovyTestCase">
      * def citiesLived = [
      *     Alice: ['NY', 'LA'],
      *     Bob: ['NY'],
@@ -8103,8 +8103,8 @@ public class DefaultGroovyMethods extends 
DefaultGroovyMethodsSupport {
      * ]
      * </pre>
      *
-     * @param self  a Map to group
-     * @return a new Map from keys to lists of elements
+     * @param self  a Map to group from original keys to lists of original 
elements
+     * @return a new Map with keys being the original elements and values 
being lists of the original keys
      * @since 6.0.0
      */
     public static <T, K> Map<K, List<T>> groupByMany(Map<T, List<K>> self) {

Reply via email to