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 -> 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 -> [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<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) {