Add MultiValuedMap.inverted()#665
Conversation
|
Hi @paulk-asert Thank you for the PR. You'll want to run 'mvn' by itself and fix errors before you push. That will run the default goal which includes all our checks. |
3cff965 to
355f42f
Compare
@garydgregory Should be fixed. Sorry for the earlier noise. |
garydgregory
left a comment
There was a problem hiding this comment.
Hello @paulk-asert
Thank you for the PR :)
I have a couple of comments.
| * | ||
| * @return the inverse MultiValuedMap | ||
| */ | ||
| default MultiValuedMap<V, K> inverse() { |
There was a problem hiding this comment.
Java 21 has java.util.List.reversed(), so how about inverted() to match the same naming pattern?
| final ArrayListValuedHashMap<V, K> result = new ArrayListValuedHashMap<>(); | ||
| MultiMapUtils.inverseInto(this, result); | ||
| return result; |
There was a problem hiding this comment.
No need to be so verbose here and for all implementations IMO:
| final ArrayListValuedHashMap<V, K> result = new ArrayListValuedHashMap<>(); | |
| MultiMapUtils.inverseInto(this, result); | |
| return result; | |
| return MultiMapUtils.inverseInto(this, new ArrayListValuedHashMap<>()); |
355f42f to
df560b8
Compare
| * @param <K> the dest key type | ||
| * @param <V> the dest value type | ||
| * @param <M> the dest multimap | ||
| * @return the destination |
There was a problem hiding this comment.
This does not make sense to me. What is the destination?
I think the Javadoc needs to make clear that the method creates a new map with the inverted keys
There was a problem hiding this comment.
The utility method doesn't create a new multimap but stores inverted mappings in the supplied collector (destination) which is also returned. The inverted method implementations supply a new multimap as the collector, but it doesn't need to be the same type or be new (to allow aggregation) when using the utility method. I could try to use "collector" everywhere and avoid "destination" if you think that would be clearer?
There was a problem hiding this comment.
I think collector would be clearer here.
For the return comment, it could say 'the updated collector'
Also it would help to document the valid types for source and collector.
There was a problem hiding this comment.
Can you clarify what you are after for source and collector? The types/generics information isn't sufficient?
| Collection<V> get(K key); | ||
|
|
||
| /** | ||
| * Returns the inverse MultiValuedMap with inverted mappings. |
There was a problem hiding this comment.
'the' => 'a new'
'the' implies that there is only one such map
There was a problem hiding this comment.
In mathematical jargon, the thing being returned is the "inverse multimap". I see what you are saying that those not knowing the math jargon might confuse that wording with meaning just one. Then again, totally forgoing the math jargon might be less clear for those that are aware of the term. I'll try to think of a middle ground.
There was a problem hiding this comment.
The comment refers to 'the MultiValueMap' which is a class, not a mathematical concept.
There was a problem hiding this comment.
Yes, it is the name of the abstraction used to represent a multimap, but I understand where you are coming from and I'll see what improvement to the wording I can think of.
| * @return the updated collector | ||
| */ | ||
| public static <K, V, M extends MultiValuedMap<K, V>> | ||
| M invertInto(MultiValuedMap<? extends V, ? extends K> source, M collector) { |
There was a problem hiding this comment.
Hi @paulk-asert
A few items here:
- I'm wondering if a simpler name like
invertwould be better since we don't usually seeIntoin method names. We know from the param names what the source and target are. Using "Into" doesn't add value for me. - The parameter name
collectormight be confusing because aCollectorin Java is something else but kind of related. Since we havesource, havingdest,destinationortargetwould be better IMO.
There was a problem hiding this comment.
Maybe invertMerge would better describe what the method does?
Also rather than source and dest, would input and output be clearer?
I don't like the abbreviation 'dest'; it's best to spell names in full as not all users will have English as a first language.
There was a problem hiding this comment.
Guava has similar methods to what is proposed here. It uses invertFrom as the utility method and inverse as the instance method. I think invert and invertMerge have some benefits. I'll ponder a change and convert collector to target or similar. Hmmm.. CollectionUtils#collect uses inputCollection and outputCollection. Maybe that convention is the way to go.
src/main/java/org/apache/commons/collections4/MultiMapUtils.java
Outdated
Show resolved
Hide resolved
| /** | ||
| * A utility method to invert the mappings from a source MultiValuedMap | ||
| * to a collector MultiValuedMap. If you are trying to create an | ||
| * inverse multimap of the same kind as the original, consider using |
There was a problem hiding this comment.
'same kind' is ambiguous.
AIUI, this method returns a MultiValuedMap; is that not the 'same kind' of map as the original?
It's not clear when one should consider using #inverted()
There was a problem hiding this comment.
Okay, the intention is that when calling inverted you have the following input -> output class relationships:
ArrayListValuedHashMap -> ArrayListValuedHashMap
ArrayListValuedLinkedHashMap -> ArrayListValuedLinkedHashMap
LinkedHashSetValuedLinkedHashMap -> LinkedHashSetValuedLinkedHashMap
LinkedHashSetValuedHashMap -> LinkedHashSetValuedHashMap
I'll try to think of better wording.
| * @param collector add value-to-key mappings here | ||
| * @param <K> the collector key type | ||
| * @param <V> the collector value type | ||
| * @param <M> the collector multimap |
There was a problem hiding this comment.
What are the valid types for M?
Are all multimap types suitable?
There was a problem hiding this comment.
I changed the wording. Let me know if it makes sense or still sounds confusing to you?
dfd9f7f to
0835f9e
Compare
| * @param outputMultimap add value-to-key mappings here | ||
| * @param <K> the outputMultimap key type | ||
| * @param <V> the outputMultimap value type | ||
| * @param <M> the outputMultimap multimap with key and value types reversed compare to inputMultimap |
There was a problem hiding this comment.
compare to => compared with
|
|
||
| /** | ||
| * A utility method to invert the mappings from an inputMultimap | ||
| * and add them to an outputMultimap. Some {@code MultiValuedMap} |
There was a problem hiding this comment.
inputMultimap => input MultiValuedMap
outputMultimap => output MultiValuedMap
inputMultimap and outputMultimap are not Java types, and AFAICT they must both be MultiValuedMap, rather than just Multimap
| * and add them to an outputMultimap. Some {@code MultiValuedMap} | ||
| * implementations support the {@link MultiValuedMap#inverted()} method. | ||
| * These typically return a new multimap instance with the same class as the original. | ||
| * Consider using this method instead if you wish to supply a particular |
There was a problem hiding this comment.
'this method' is ambiguous here: does it refer to the method inverted() which has just been described, or the method in this class?
I think it would be clearer to describe the usage for the current class method before explaining that there are alternatives.
0835f9e to
6f0275e
Compare
This PR adds an inverse method into the following multimap implementations:
ArrayListValuedHashMapArrayListValuedLinkedHashMapHashSetValuedHashMapHashSetValuedLinkedHashMapThere is also an
inverseIntomethod added toMultiMapUtilsto handle the case of a heterogenous collector.As well as a test case to the relevant source files. Decorated multimaps throw
UnsupportedOperationExceptionby default.