Reputation: 3761
How can I sort a TreeMap<String, String>
in CASE_INSENSITIVE_ORDER
based on key.
Currently, by default, it is sorted like:
A B C D a b c d
I want it to be like:
a A b B c C d D
Upvotes: 4
Views: 7303
Reputation: 11
The accepted answer is wrong - 'a' and 'A' are the same key ignoring case. Here is some toy code to prove this and provide the sketch of an alternative that answers the question.
import java.util.Comparator;
import java.util.TreeMap;
public class TreeMapComparatorTest {
public static void main(String[] args) {
TreeMap<String, Integer> caseInsensitive = new TreeMap<String, Integer>(String.CASE_INSENSITIVE_ORDER);
caseInsensitive.put("a", 97);
caseInsensitive.put("A", 65);
// prints [a]
System.out.println(caseInsensitive.keySet());
TreeMap<String, Integer> customComparator = new TreeMap<String, Integer>(new Comparator<String>(){
@Override
public int compare(String o1, String o2) {
// assuming only single letters for a smaller example...
Character c1 = o1.charAt(0);
Character c2 = o2.charAt(0);
Character upper1 = Character.toUpperCase(c1);
Character upper2 = Character.toUpperCase(c2);
if(c1.compareTo(c2) == 0){
// exactly the same char
return 0;
}else if (upper1.compareTo(upper2) == 0){
// return lowercase first for same upper chars
return -c1.compareTo(c2);
}else{
// order alphabetically
return upper1.compareTo(upper2);
}
}
});
customComparator.put("a", 97);
customComparator.put("A", 65);
customComparator.put("b", 98);
customComparator.put("B", 66);
// prints [a, A, b, B]
System.out.println(customComparator.keySet());
}
}
Upvotes: 1
Reputation: 313
The String.CASE_INSENSITIVE_ORDER
- comparator does not sort as required in the question. The result that was asked for was an order like
a, A, b, B ...
Instead it handles "a" and "A" as "equal", which means an entry with key "a" would override an entry with the key "A" in the sorted-map. The outcome would rather be something like "a, B", depending on what was added to the map last.
One way to achieve the behaviour would be to use a custom-comparator like this:
Comparator<String> comparator = new Comparator<String>() {
public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
if (isAtoZ(c1) && isAtoZ(c2)) {
return getSortPosition(c1) - getSortPosition(c2);
}
return c1 - c2;
}
}
return n1 - n2;
}
private boolean isAtoZ(char c) {
return c > 64 && c < 123;
}
private int getSortPosition(char c) {
if (c < 91) {
// upper case
return 2 * (c - 64); // A = 2, B = 4 ...
} else if (c > 96) {
// lower case
return (2 * (c - 96)) - 1; // a = 1, b = 3 ...
} else {
// between Z and a: [, /, ], ^, _, `
return c; // higher than the value for 'z'
}
}
};
Upvotes: 6
Reputation: 13907
You can pass the case insensitive order comparator as the argument of one of TreeMap's constructors:
TreeMap<String, String> treemap = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
Upvotes: 4
Reputation: 21971
Call String#CASE_INSENSITIVE_ORDER to TreeMap
constructor,
Map<String, String> tree = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
Upvotes: 1
Reputation: 47290
Use a Comparator in the TreeMap constructor. And String.CASE_INSENSITIVE_ORDER.
Upvotes: -1