I need a multi map which keys are case insensitive. is there such implementation in google collections?
-
Google collections is deprectated, adding guava tag, as it is the successor of google collections – Sean Patrick Floyd Jan 04 '11 at 10:51
4 Answers
Here is a case insensitive version of a ForwardingMap
:
public class CaseInsensitiveForwardingMap<V> extends ForwardingMap<String, V>
implements Serializable{
private static final long serialVersionUID = -7741335486707072323L;
// default constructor
public CaseInsensitiveForwardingMap(){
this(new HashMap<String, V>());
}
// constructor with a supplied map
public CaseInsensitiveForwardingMap(final Map<String, V> inner){
this.inner = inner;
}
private final Map<String, V> inner;
@Override
protected Map<String, V> delegate(){
return inner;
}
// convert keys to lower case Strings, preserve null keys
private static String lower(final Object key){
return key == null ? null : key.toString().toLowerCase();
}
@Override
public V get(final Object key){ return inner.get(lower(key)); }
@Override
public void putAll(final Map<? extends String, ? extends V> map){
if(map == null || map.isEmpty()){ inner.putAll(map); }
else{
for(final Entry<? extends String, ? extends V> entry :
map.entrySet()){
inner.put(lower(entry.getKey()), entry.getValue());
}
}
}
@Override
public V remove(final Object object){ return inner.remove(lower(object)); }
@Override
public boolean containsKey(final Object key){
return inner.containsKey(lower(key));
}
@Override
public V put(final String key, final V value){
return inner.put(lower(key), value);
}
}
Using this map, you can create the MultiMap
using the Supplier methods in MultiMaps
.
Example:
Map<String, Collection<String>> map =
new CaseInsensitiveForwardingMap<Collection<String>>();
Multimap<String, String> caseInsensitiveMultiMap =
Multimaps.newMultimap(map, new Supplier<Collection<String>>(){
@Override
public Collection<String> get(){ return Sets.newHashSet(); }
});
Caveat: keySet()
will return lowercase values only, regardless how the keys were entered.

- 292,901
- 67
- 465
- 588
-
3Note that it's better to use the String.toUpperCase instead of String.toLowerCase for this, since some characters are mapped to several characters while being uppercased, but not while being lowercased. For instance, the character `\u00df` is mapped to the uppercase `\u0053\u0053`, whereas `\u0053\u0053` is mapped to the lowercase `\u0073\u0073`. But obviously `\u00df` isn't considered the the same as `\u0073\u0073` whereas it semantically is. – Olivier Grégoire Jan 21 '11 at 14:58
-
1@OlivierGrégoire if you look into the source-code of `String.equalsIgnoreCase()` you will discover that you need to compare *both* the uppercase and lowercase form of a character to ignore case to be safe across all locales. Checking only one form will fail for some languages. – Gili Sep 30 '18 at 01:46
Couldn't you use a Map<String,List<Payload>>
and give it a Comparator<String>
which did a case-insensitive compare?
It appears that neither Google Collections nor Apache Collection frameworks have a multimap that accepts a Comparator for evaluating key equality.

- 6,112
- 3
- 33
- 43
-
3Use [MultiMaps.newListMultiMap()](http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/Multimaps.html#newListMultimap%28java.util.Map%2C%20com.google.common.base.Supplier%29) and supply a `TreeMap` with a custom comparator – Sean Patrick Floyd Jan 04 '11 at 11:19
-
You could define a case-insensitive String Comparator using a Collator. Then create a TreeMultimap with keys sorted by that Comparator.

- 1,986
- 13
- 12
No, but presumably you're using String keys? If so, why not just normalise all access to a regular multimap? For the 80% case, that'll be making all calls puts and gets lowercase the key.
For a full discussion of the issues with case-insensitive multimaps, see this google group discussion

- 23,950
- 10
- 60
- 73