Question

public final Comparator<String> ID_IGN_CASE_COMP = new Comparator<String>() {

        public int compare(String s1, String s2) {
            return s1.compareToIgnoreCase(s2);
        }
    };

private Map< String, Animal > _animals = new TreeMap< String, Animal >(ID_IGN_CASE_COMP);

My problem is, how to use method get(id) ignoring the given comparator. I want the map to be order by Case Insensitive but, I want it to be case sensitive when I fetch the values by a given key.

Was it helpful?

Solution

I think the answer is easy. Implement your own comparator that does a case insensitive sort but does NOT return 0 for "A" and "a"... sort them too.

The issue is that your comparator returns 0 for the compare( "A", "a" ) case which means it is the same key as far as the map is concerned.

Use a comparator like:

public final Comparator<String> ID_IGN_CASE_COMP = new Comparator<String>() {

    public int compare(String s1, String s2) {
        int result = s1.compareToIgnoreCase(s2);
        if( result == 0 )
            result = s1.compareTo(s2);
        return result;
    }
};

Then all keys will go in regardless of case and "a" and "A" will still be sorted together.

In other words, get("a") will give you a different value from get("A")... and they will both show up in keySet() iterators. They will just be sorted together.

OTHER TIPS

In a TreeMap, adding two keys a and b (in that order) so that compare(a, b) returns 0 will result in that the latest added entry (b) will overwrite the first one (a).

In your case, this means that there will never be any use for case insensitive get(id).

quoting http://java.sun.com/javase/6/docs/api/java/util/TreeMap.html

Note that the ordering maintained by a sorted map (whether or not an explicit comparator is provided) must be consistent with equals if this sorted map is to correctly implement the Map interface. (See Comparable or Comparator for a precise definition of consistent with equals.) This is so because the Map interface is defined in terms of the equals operation, but a map performs all key comparisons using its compareTo (or compare) method, so two keys that are deemed equal by this method are, from the standpoint of the sorted map, equal. 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 is probably not what you want.

If the map is comparably small and you don't need to fetch the sorted entries very many times, a solution is to use a HashMap (or a TreeMap without explicitly setting the comparator), and sort the entries case-insensitively when you need them ordered.

You'll have to use two separate TreeMaps for that, with the same contents but different comparators.

maybe it'll do the job:

    new Comparator<String>(){
    public int compare(String s1, String s2)
    {
        String s1n = s1.toLowerCase();
        String s2n = s2.toLowerCase();

        if(s1n.equals(s2n))
        {
            return s1.compareTo(s2);
        }
        return s1n.compareTo(s2n);
    }
};
                                                    }

you need a multimap: each entry of this multimap keeps the case insensitive keys and aanother map with the original keys as value.

There are many freely usable implementations of multimaps such as Common Collections, Google Collections, etc

In addition to all the other answers and agreeing, that it is impossible to have a single TreeMap structure with different comparators:

From your question I understand that you have two requirements: the data model shall be case sensitive (you want the case sensitive values when you use get()), the presenter shall be case insensitive (you want an case sensitive ordering, presentation is just an assumption).

Let's assume, we populate the Map with the mappings (aa,obj1), (aA,obj2), (Aa,obj3), (AA,obj4). The iterator will provides the values in the order: (obj4, obj3, obj2, obj1)(*). Now which order do you expect if the map was ordered case-insensitive? All four keys would be equal and the order undefined. Or are you looking for a solution that would resolve the collection {obj1, obj2, obj3, obj4} for the key 'AA'? But that's a different approach.

SO encourages the community to be honest: therefore my advice at this point is to look at your requirement again :)

(*) not tested, assumed that 'A' < 'a' = true.

Use floorEntry and then higherEntry in a loop to find the entries case-insensitively; stop when you find the exact key match.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top