String is as a key of the HashMap When you pass the key to retrieve its value, the hash code is calculated again, and the value in the position represented by the hash code is fetched (if both hash codes are equal).
Map is one of the most common data structures in Java, and String is one of the most common types for a map's key. By default, a map of this sort has case-sensitive keys.
In this example, we will show you how to check HashSet contains element case insensitive in Java. contains() method of Collection interface returns true if this set contains the specified element. But the problem is contains() method only check the equality of element (case sensitive).
Map<String, String> nodeMap =
new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
That's really all you need.
As suggested by Guido García in their answer here:
import java.util.HashMap;
public class CaseInsensitiveMap extends HashMap<String, String> {
@Override
public String put(String key, String value) {
return super.put(key.toLowerCase(), value);
}
// not @Override because that would require the key parameter to be of type Object
public String get(String key) {
return super.get(key.toLowerCase());
}
}
Or
https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/map/CaseInsensitiveMap.html
One approach is to create a custom subclass of the Apache Commons AbstractHashedMap
class, overriding the hash
and isEqualKeys
methods to perform case insensitive hashing and comparison of keys. (Note - I've never tried this myself ...)
This avoids the overhead of creating new objects each time you need to do a map lookup or update. And the common Map
operations should O(1) ... just like a regular HashMap
.
And if you are prepared to accept the implementation choices they have made, the Apache Commons CaseInsensitiveMap
does the work of customizing / specializing AbstractHashedMap
for you.
But if O(logN) get
and put
operations are acceptable, a TreeMap
with a case insensitive string comparator is an option; e.g. using String.CASE_INSENSITIVE_ORDER
.
And if you don't mind creating a new temporary String object each time you do a put
or get
, then Vishal's answer is just fine. (Though, I note that you wouldn't be preserving the original case of the keys if you did that ...)
Subclass HashMap
and create a version that lower-cases the key on put
and get
(and probably the other key-oriented methods).
Or composite a HashMap
into the new class and delegate everything to the map, but translate the keys.
If you need to keep the original key you could either maintain dual maps, or store the original key along with the value.
Two choices come to my mind:
s.toUpperCase().hashCode();
as the key of the Map
.TreeMap<String>
with a custom Comparator
that ignore the case.Otherwise, if you prefer your solution, instead of defining a new kind of String, I would rather implement a new Map with the required case insensibility functionality.
Wouldn't it be better to "wrap" the String in order to memorize the hashCode. In the normal String class hashCode() is O(N) the first time and then it is O(1) since it is kept for future use.
public class HashWrap {
private final String value;
private final int hash;
public String get() {
return value;
}
public HashWrap(String value) {
this.value = value;
String lc = value.toLowerCase();
this.hash = lc.hashCode();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o instanceof HashWrap) {
HashWrap that = (HashWrap) o;
return value.equalsIgnoreCase(that.value);
} else {
return false;
}
}
@Override
public int hashCode() {
return this.hash;
}
//might want to implement compare too if you want to use with SortedMaps/Sets.
}
This would allow you to use any implementation of Hashtable in java and to have O(1) hasCode().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With