Case-insensitive map key where key is Pair<String, String>

89 Views Asked by At

I have Map in Java:

 Map<Pair<String, String>, MyClass> myMap;

I need the Pair to NOT be case-sensitive. The solution in case of regular string key is simple:

 TreeMap<String, MyClass> myMap= new TreeMap(String.CASE_INSENSITIVE_ORDER);

But, what about case of strings-pair key?

I need to compare first (left) value case-sensitive and then second (right) case-insensitive.

3

There are 3 best solutions below

4
dan1st might be happy again On

If you wanted to use TreeMap, you can write a custom Comparator as mentioned in the comments by Federico klez Culloca. See also the other answers on how to do this. However, TreeMap should only be used if you really want your entries to by sorted by key.

If you don't need sorting, you can also create a custom key class with hashCode and equals methods and use a HashMap:

record CaseInsensitiveStringPair(String first, String second){
    @Override
    public boolean equals(Object other){
        return other instanceof CaseInsensitiveStringPair o &&
            first().toLowerCase().equals(o.first().toLowerCase()) &&
            second().toLowerCase().equals(o.second().toLowerCase()) 
    }
    @Override
    public int hashCode(){
        return Objects.hash(first().toLowerCase(), second().toLowerCase());
    }
}

If it's ok if the Strings are stored in lowercase form, you could do that as well:

record CaseInsensitiveStringPair(String first, String second){
    public CaseInsensitiveStringPair(String first, String second){
        this.first=first.toLowerCase();
        this.second=second.toLowerCase();
    }
}

and then use a

Map<CaseInsensitiveStringPair, MyClass> map = new HashMap<>();
2
Влад On

I don't know anything about your Pair object, unfortunately. However, I do know that TreeMap has a constructor with a Comparator parameter, so you can implement your own:

class CaseInsensitiveComparator implements Comparator<Pair<String, String>> {
    @Override
    public int compare(Pair<String, String> o1, Pair<String, String> o2) {
        return o1.getKey().compareToIgnoreCase(o2.getKey());
    }
}

and then you can simply do:

 Map<Pair<String, String>, MyClass> myMap = new TreeMap(new CaseInsensitiveComparator())
3
Chaosfire On

You can use Comparator.comparing()

Accepts a function that extracts a Comparable sort key from a type T, and returns a Comparator that compares by that sort key.

and Comparator.thenComparing()

Returns a lexicographic-order comparator with a function that extracts a key to be compared with the given Comparator.

to easily build a comparator prioritizing first in comparison, and then second if first are equal.

Comparator<Pair> comparator = Comparator.comparing(Pair::first)//compare first case-sensitive
            .thenComparing(Pair::second, String.CASE_INSENSITIVE_ORDER);//case-insensitive comparison of second if first are equal