This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-collections.git
The following commit(s) were added to refs/heads/master by this push:
new d7a8201d5 provide an inverse method for multimaps
d7a8201d5 is described below
commit d7a8201d50f1a5c291d64015200a9648c6eb6ac2
Author: Paul King <[email protected]>
AuthorDate: Fri Dec 12 21:15:50 2025 +1000
provide an inverse method for multimaps
---
.../apache/commons/collections4/MultiMapUtils.java | 22 ++++++++++++++++++
.../commons/collections4/MultiValuedMap.java | 11 +++++++++
.../multimap/ArrayListValuedHashMap.java | 6 +++++
.../multimap/ArrayListValuedLinkedHashMap.java | 6 +++++
.../multimap/HashSetValuedHashMap.java | 6 +++++
.../multimap/LinkedHashSetValuedLinkedHashMap.java | 6 +++++
.../commons/collections4/MultiMapUtilsTest.java | 26 ++++++++++++++++++++++
.../multimap/ArrayListValuedHashMapTest.java | 13 +++++++++++
.../multimap/ArrayListValuedLinkedHashMapTest.java | 13 +++++++++++
.../multimap/HashSetValuedHashMapTest.java | 13 +++++++++++
.../LinkedHashSetValuedLinkedHashMapTest.java | 13 +++++++++++
.../multimap/TransformedMultiValuedMapTest.java | 6 +++++
12 files changed, 141 insertions(+)
diff --git a/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
b/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
index ef7fc8c96..c698a38e5 100644
--- a/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
+++ b/src/main/java/org/apache/commons/collections4/MultiMapUtils.java
@@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import org.apache.commons.collections4.bag.HashBag;
@@ -170,6 +171,27 @@ public class MultiMapUtils {
return map == null || map.isEmpty();
}
+ /**
+ * A utility method to invert the mappings from an input MultiValuedMap
+ * and add them to an output MultiValuedMap. Use this method to have
complete
+ * control of the output MultiValuedMap or when merging several inverse
mappings.
+ * In simple cases, consider just using the {@link
MultiValuedMap#inverted()} method.
+ *
+ * @param input take key-to-value mappings from here
+ * @param output add value-to-key mappings here
+ * @param <K> the output MultiValuedMap key type
+ * @param <V> the output MultiValuedMap value type
+ * @param <M> the output MultiValuedMap with key and value types reversed
compared with input
+ * @return the updated output MultiValuedMap
+ */
+ public static <K, V, M extends MultiValuedMap<K, V>>
+ M invert(MultiValuedMap<? extends V, ? extends K> input, M output) {
+ for (Map.Entry<? extends V, ? extends K> e : input.entries()) {
+ output.put(e.getValue(), e.getKey());
+ }
+ return output;
+ }
+
/**
* Creates a {@link ListValuedMap} with an {@link java.util.ArrayList
ArrayList} as
* collection class to store the values mapped to a key.
diff --git a/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
b/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
index 96d2f6b08..350e74e7e 100644
--- a/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
+++ b/src/main/java/org/apache/commons/collections4/MultiValuedMap.java
@@ -140,6 +140,17 @@ public interface MultiValuedMap<K, V> {
*/
Collection<V> get(K key);
+ /**
+ * Returns a new MultiValuedMap with inverted mappings.
+ * The new multimap will have a value-to-key mapping
+ * for each key-to-value mapping in the original.
+ *
+ * @return a new MultiValuedMap with inverted mappings
+ */
+ default MultiValuedMap<V, K> inverted() {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Returns {@code true} if this map contains no key-value mappings.
*
diff --git
a/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java
b/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java
index a9d2a1153..47586dc63 100644
---
a/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java
+++
b/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMap.java
@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import org.apache.commons.collections4.MultiMapUtils;
import org.apache.commons.collections4.MultiValuedMap;
/**
@@ -118,6 +119,11 @@ public class ArrayListValuedHashMap<K, V> extends
AbstractListValuedMap<K, V>
return new ArrayList<>(initialListCapacity);
}
+ @Override
+ public ArrayListValuedHashMap<V, K> inverted() {
+ return MultiMapUtils.invert(this, new ArrayListValuedHashMap<V, K>());
+ }
+
/**
* Deserializes an instance from an ObjectInputStream.
*
diff --git
a/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMap.java
b/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMap.java
index f1b797b53..2556ab3f7 100644
---
a/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMap.java
+++
b/src/main/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMap.java
@@ -25,6 +25,7 @@ import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
+import org.apache.commons.collections4.MultiMapUtils;
import org.apache.commons.collections4.MultiValuedMap;
/**
@@ -118,6 +119,11 @@ public class ArrayListValuedLinkedHashMap<K, V> extends
AbstractListValuedMap<K,
return new ArrayList<>(initialListCapacity);
}
+ @Override
+ public ArrayListValuedLinkedHashMap<V, K> inverted() {
+ return MultiMapUtils.invert(this, new
ArrayListValuedLinkedHashMap<>());
+ }
+
/**
* Deserializes an instance from an ObjectInputStream.
*
diff --git
a/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java
b/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java
index b122e2c41..184730cbf 100644
---
a/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java
+++
b/src/main/java/org/apache/commons/collections4/multimap/HashSetValuedHashMap.java
@@ -24,6 +24,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import org.apache.commons.collections4.MultiMapUtils;
import org.apache.commons.collections4.MultiValuedMap;
/**
@@ -117,6 +118,11 @@ public class HashSetValuedHashMap<K, V> extends
AbstractSetValuedMap<K, V>
return new HashSet<>(initialSetCapacity);
}
+ @Override
+ public HashSetValuedHashMap<V, K> inverted() {
+ return MultiMapUtils.invert(this, new HashSetValuedHashMap<V, K>());
+ }
+
/**
* Deserializes an instance from an ObjectInputStream.
*
diff --git
a/src/main/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMap.java
b/src/main/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMap.java
index c8be8751d..c381893b6 100644
---
a/src/main/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMap.java
+++
b/src/main/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMap.java
@@ -24,6 +24,7 @@ import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
+import org.apache.commons.collections4.MultiMapUtils;
import org.apache.commons.collections4.MultiValuedMap;
/**
@@ -117,6 +118,11 @@ public class LinkedHashSetValuedLinkedHashMap<K, V>
extends AbstractSetValuedMap
return new LinkedHashSet<>(initialSetCapacity);
}
+ @Override
+ public LinkedHashSetValuedLinkedHashMap<V, K> inverted() {
+ return MultiMapUtils.invert(this, new
LinkedHashSetValuedLinkedHashMap<V, K>());
+ }
+
/**
* Deserializes an instance from an ObjectInputStream.
*
diff --git
a/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
b/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
index 14f177f2b..7ff98ba07 100644
--- a/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
+++ b/src/test/java/org/apache/commons/collections4/MultiMapUtilsTest.java
@@ -29,6 +29,8 @@ import java.util.List;
import java.util.Set;
import org.apache.commons.collections4.multimap.ArrayListValuedHashMap;
+import org.apache.commons.collections4.multimap.HashSetValuedHashMap;
+import
org.apache.commons.collections4.multimap.LinkedHashSetValuedLinkedHashMap;
import org.junit.jupiter.api.Test;
/**
@@ -116,6 +118,30 @@ class MultiMapUtilsTest {
assertEquals(new HashSet<>(Arrays.asList(values)), set);
}
+ @Test
+ void testInvert() {
+ final HashSetValuedHashMap<String, String> usages = new
HashSetValuedHashMap<>();
+
+ final LinkedHashSetValuedLinkedHashMap<String, String> deps = new
LinkedHashSetValuedLinkedHashMap<>();
+ deps.put("commons-configuration2", "commons-logging");
+ deps.put("commons-configuration2", "commons-lang3");
+ deps.put("commons-configuration2", "commons-text");
+ deps.put("commons-beanutils", "commons-collections");
+ deps.put("commons-beanutils", "commons-logging");
+ MultiMapUtils.invert(deps, usages);
+ final Set<String> loggingUsagesCompile = usages.get("commons-logging");
+ assertEquals("[commons-configuration2, commons-beanutils]",
loggingUsagesCompile.toString());
+ final Set<String> codecUsagesCompile = usages.get("commons-codec");
+ assertEquals("[]", codecUsagesCompile.toString());
+
+ final LinkedHashSetValuedLinkedHashMap<String, String> optionalDeps =
new LinkedHashSetValuedLinkedHashMap<>();
+ optionalDeps.put("commons-configuration2", "commons-codec");
+ optionalDeps.put("commons-collections", "commons-codec");
+ MultiMapUtils.invert(optionalDeps, usages);
+ final Set<String> codecUsagesAll = usages.get("commons-codec");
+ assertEquals("[commons-collections, commons-configuration2]",
codecUsagesAll.toString());
+ }
+
@Test
void testIsEmptyWithEmptyMap() {
assertTrue(MultiMapUtils.isEmpty(new ArrayListValuedHashMap<>()));
diff --git
a/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMapTest.java
b/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMapTest.java
index 47e9a63e6..f65ee297c 100644
---
a/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMapTest.java
+++
b/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedHashMapTest.java
@@ -93,6 +93,19 @@ public class ArrayListValuedHashMapTest<K, V> extends
AbstractMultiValuedMapTest
assertNotSame(map1.hashCode(), map2.hashCode());
}
+ @Test
+ void testInverted() {
+ final ArrayListValuedHashMap<String, String> shopping = new
ArrayListValuedHashMap<>(4);
+ shopping.put("Alice", "Bread");
+ shopping.put("Alice", "Milk");
+ shopping.put("Alice", "Milk");
+ shopping.put("Bob", "Pizza");
+ shopping.put("Bob", "Bread");
+ shopping.put("Bob", "Bread");
+ assertEquals("{Pizza=[Bob], Bread=[Bob, Bob, Alice], Milk=[Alice,
Alice]}",
+ shopping.inverted().toString());
+ }
+
@Test
@SuppressWarnings("unchecked")
void testListValuedMapAdd() {
diff --git
a/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMapTest.java
b/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMapTest.java
index 74353b50a..550a19240 100644
---
a/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMapTest.java
+++
b/src/test/java/org/apache/commons/collections4/multimap/ArrayListValuedLinkedHashMapTest.java
@@ -99,6 +99,19 @@ public class ArrayListValuedLinkedHashMapTest<K, V> extends
AbstractMultiValuedM
assertNotSame(map1.hashCode(), map2.hashCode());
}
+ @Test
+ void testInverted() {
+ final ArrayListValuedLinkedHashMap<String, String> shopping = new
ArrayListValuedLinkedHashMap<>(4);
+ shopping.put("Alice", "Bread");
+ shopping.put("Alice", "Milk");
+ shopping.put("Alice", "Milk");
+ shopping.put("Bob", "Pizza");
+ shopping.put("Bob", "Bread");
+ shopping.put("Bob", "Bread");
+ assertEquals("{Bread=[Alice, Bob, Bob], Milk=[Alice, Alice],
Pizza=[Bob]}",
+ shopping.inverted().toString());
+ }
+
@Test
@SuppressWarnings("unchecked")
void testListValuedMapAdd() {
diff --git
a/src/test/java/org/apache/commons/collections4/multimap/HashSetValuedHashMapTest.java
b/src/test/java/org/apache/commons/collections4/multimap/HashSetValuedHashMapTest.java
index 7b50d6cd1..419ae3814 100644
---
a/src/test/java/org/apache/commons/collections4/multimap/HashSetValuedHashMapTest.java
+++
b/src/test/java/org/apache/commons/collections4/multimap/HashSetValuedHashMapTest.java
@@ -110,6 +110,19 @@ public class HashSetValuedHashMapTest<K, V> extends
AbstractMultiValuedMapTest<K
assertEquals("{}", map3.toString());
}
+ @Test
+ void testInverted() {
+ final HashSetValuedHashMap<String, String> dependencies = new
HashSetValuedHashMap<>();
+ dependencies.put("commons-configuration2", "commons-logging");
+ dependencies.put("commons-configuration2", "commons-lang3");
+ dependencies.put("commons-configuration2", "commons-text");
+ dependencies.put("commons-beanutils", "commons-collections");
+ dependencies.put("commons-beanutils", "commons-logging");
+ final Set<String> loggingUsages =
dependencies.inverted().get("commons-logging");
+ assertEquals("[commons-beanutils, commons-configuration2]",
+ loggingUsages.toString());
+ }
+
@Test
@SuppressWarnings("unchecked")
void testSetValuedMapAdd() {
diff --git
a/src/test/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMapTest.java
b/src/test/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMapTest.java
index 2b37cb76d..561432363 100644
---
a/src/test/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMapTest.java
+++
b/src/test/java/org/apache/commons/collections4/multimap/LinkedHashSetValuedLinkedHashMapTest.java
@@ -96,6 +96,19 @@ public class LinkedHashSetValuedLinkedHashMapTest<K, V>
extends AbstractMultiVal
assertEquals("{}", map3.toString());
}
+ @Test
+ void testInverted() {
+ final LinkedHashSetValuedLinkedHashMap<String, String> citiesLived =
new LinkedHashSetValuedLinkedHashMap<>(4);
+ citiesLived.put("Alice", "N.Y.");
+ citiesLived.put("Alice", "L.A.");
+ citiesLived.put("Alice", "Chicago");
+ citiesLived.put("Bob", "N.Y.");
+ citiesLived.put("Cara", "L.A.");
+ citiesLived.put("Cara", "Chicago");
+ assertEquals("{N.Y.=[Alice, Bob], L.A.=[Alice, Cara], Chicago=[Alice,
Cara]}",
+ citiesLived.inverted().toString());
+ }
+
@Test
void testLinkedHashSetValuedLinkedHashMap_2() {
final Map<K, V> map = new HashMap<>();
diff --git
a/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java
b/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java
index 37ef87d8f..d83b47108 100644
---
a/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java
+++
b/src/test/java/org/apache/commons/collections4/multimap/TransformedMultiValuedMapTest.java
@@ -19,6 +19,7 @@ package org.apache.commons.collections4.multimap;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Collection;
@@ -99,6 +100,11 @@ public class TransformedMultiValuedMapTest<K, V> extends
AbstractMultiValuedMapT
assertTrue(transMap.get((K) "D").contains(Integer.valueOf(4)));
}
+ @Test
+ void testInvertedIsUnsupportedByDefault() {
+ assertThrows(UnsupportedOperationException.class, () ->
makeObject().inverted());
+ }
+
@Test
@SuppressWarnings("unchecked")
void testKeyTransformedMap() {