简体   繁体   中英

Java - How to sort a map values according to their first letter?

I have a Java map that i use this code to sort its String values alphabetically:

public <K, V> LinkedHashMap<K, V> sortMapByValues( Map<K, V> map ) {
    SortedSet<Map.Entry<K, V>> sortedEntries = new TreeSet<Map.Entry<K, V>>(
        new Comparator<Map.Entry<K, V>>() {
            @Override 
            public int compare( Map.Entry<K, V> e1, Map.Entry<K, V> e2 ) {
                // Sort this word alphabetically in the map : 
                String a = (String)e1.getValue();
                String b = (String)e2.getValue();

                int diff = a.compareToIgnoreCase( b );

                if (diff == 0) 
                    diff = a.compareTo(b);  

                return diff != 0 ? diff : 1;  // Fix words having the same spelling.
            }
        }
    );

    sortedEntries.addAll( map.entrySet() );

    LinkedHashMap<K, V> sortedMap = new LinkedHashMap<K, V>();

    for( Map.Entry<K, V> sortedEntry: sortedEntries )
        sortedMap.put( sortedEntry.getKey(), sortedEntry.getValue() );

    return sortedMap;
}

Since the Map has thousands of values, the above code works fast enough giving the result that i want rapidly. Now i need to change this code and update it to sort the Map values according to another condition instead of sorting it alphabetically.

I have a variant ArrayList of letters, like:

ArrayList lettersArrayList = new ArrayList<String>( Arrays.asList( "E", "C", "A", "Z", "Q", "R", "B", "L", "D", ... ) );

The letter values inside this ArrayList are specified by the user so they might have any other letter values and order. I need to sort the String values of the Map according to this ArrayList, so the words starting with "E" come first, then comes the ones that start with "C", and so on. Is this possible?

First of all, your comparator is incorrect:

return diff != 0 ? diff : 1;

If a and b have the same spelling, comparing a to b gives 1, meaning that a > b , and comparing b to a also gives 1, meaning that b > a . You could use

return diff != 0 ? diff : Integer.compare(System.identityHashCode(e1), System.identityHashCode(e2));

to be (almost) correct. This could still make two entries equal when they're actually different if you're using an awful lot of memory and two separate objects happen to end up with the same system hashcode, which is very, very unlikely.

Now, to answer your question, all you need is to compare the indices of the first letters of your two entries:

String a = (String)e1.getValue();
String b = (String)e2.getValue();

int index1 = list.indexOf(a.substring(0, 1));
int index2 = list.indexOf(b.substring(0, 1));

int diff = Integer.compare(index1, index2);

This will work but will be extremely inefficient, because

  • indexOf() is O(n)
  • you'd better use Character rather that String to store a single character.

So, instead of a List<String> to store the letters, you should use a HashMap<Character, Integer> , where each letter would be associated with its position. A lookup in this map would be O(1), making the comparator much faster.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM