0

Possible Duplicate:
Case insensitive string as HashMap key

I have a Hashmap with a String as the key and an integer as the value. Now, I am using the get method to get the values, where the string matches with the key value.


HashMap<String,Integer> map= new HashMap<String,Integer>();
// Populate the map

System.out.println(map.get("mystring"));

I want this string comparison to be case insensitive. Is there anyway I can do that ?


For example, I want it to return the same result in the following cases:


map.get("hello");
map.get("HELLO");
map.get("Hello");
Community
  • 1
  • 1
OneMoreError
  • 7,518
  • 20
  • 73
  • 112

5 Answers5

3

If performance is not critical, you can use a TreeMap. Output of the code below:

1
6
6

Note that the behaviour you require is not compliant with Map#get contract:

More formally, if this map contains a mapping from a key k to a value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null. (There can be at most one such mapping.)

public static void main(String[] args) {
    Map<String, Integer> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);

    map.put("hello", 3);
    map.put("HELLO", 6);
    System.out.println(map.size());
    System.out.println(map.get("heLLO"));
    System.out.println(map.get("hello"));
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • +1 Using a custom comparator is cleaner than sub classing. – Peter Lawrey Sep 25 '12 at 17:24
  • That will not work. The comparator is not consistent with `equals()`, which, according to [the docs](http://docs.oracle.com/javase/6/docs/api/java/util/TreeMap.html), is a requirement for a `TreeMap` to correctly implement the `Map` interface. – Ted Hopp Sep 25 '12 at 17:26
  • @TedHopp The behaviour required by the OP is not consistent with `String#equals`. So I don't see how you can implement it in a way that complies with Map's contract (including using the subclassing / wrapper options proposed in other answers). – assylias Sep 25 '12 at 17:27
  • @TedHopp Added a comment to clarify. – assylias Sep 25 '12 at 17:30
  • Good point -- OP's requirement technically isn't for a `Map` (according to Java's definition of a `Map`). – Ted Hopp Sep 25 '12 at 17:34
  • @assylias Watch out for the police squad! I had a similar [answer](http://stackoverflow.com/questions/12508332/how-to-insert-into-set-without-changing-the-equals-and-hashcode/12508664#12508664) that was frowned upon. +1 on this one from me! – maba Sep 25 '12 at 19:04
  • 1
    @TedHopp: "The behavior of a sorted map is well-defined even if its ordering is inconsistent with equals; it just fails to obey the general contract of the Map interface." This would be my solution. – Louis Wasserman Sep 25 '12 at 22:21
1

You can do

Map<String,Integer> map= new HashMap<String,Integer>() {
    @Override
    public Integer put(String key, Integer value) {
      return super.put(key.toLowerCase(), value);
    }

    @Override
    public Integer get(Object o) {
       return super.get(o.toString().toLowerCase());
    }
};
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 4
    You also need to override `put` to lower-case all keys. Otherwise you can never retrieve values stored under keys that are not already lower case. You probably also have to deal with `putAll` and the constructor that takes another map as an argument. – Ted Hopp Sep 25 '12 at 17:19
  • I get that you are doing a lookup for the tolowercase of the query string, but what if the lower case version was never inserted? – Tudor Sep 25 '12 at 17:19
  • Added put but not `contains` and a few others you might need. – Peter Lawrey Sep 25 '12 at 17:22
  • 1
    A wrapper class is probably a better approach than subclassing. It's an easier way to deal with those "others". – Ted Hopp Sep 25 '12 at 17:23
1

You can create a wrapper class that will wrap the HashMap and implement the get and put methods.

Mr T.
  • 4,278
  • 9
  • 44
  • 61
1
HashMap<InsensitiveString,Integer> map= new HashMap<>();

map.get(new InsensitiveString("mystring"));

---

public class InsensitiveString

    final String string;

    public InsensitiveString(String string)
        this.string = string;

    public int hashCode()
        calculate hash code based on lower case of chars in string

    public boolean equals(Object that)
        compare 2 strings insensitively
irreputable
  • 44,725
  • 9
  • 65
  • 93
0

Write a wrapper method which will put String like below a

map.put(string.toLowerCase());

and get method

map.get(string.toLowerCase());
Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72