2

I have an HashMap :

private Map<String,Integer> matchesWonByTeam= new HashMap<String,Integer>();
  • I need to order those teams by matches won (value) and return an ArrayList with the names of the teams.
  • If any of those teams have the same amount of matches won they need to be alphabetically ordered.

What is the shortest and simplest way to do that using Collections and Comparators?

dbank
  • 1,173
  • 1
  • 17
  • 29
  • 1
    HashMaps are unordered. Move the names to an ArrayList and order them there according to the values retrieved from the HashMap. – MarsAtomic Feb 25 '15 at 01:51
  • Iterate thru them and add them to a `TreeMap` (which keeps them sorted if you provide the `Comparator` at creation time) – blurfus Feb 25 '15 at 01:55
  • maybe a duplicate of this http://stackoverflow.com/questions/109383/how-to-sort-a-mapkey-value-on-the-values-in-java – harshtuna Feb 25 '15 at 02:22

5 Answers5

5

Here's some Java 8 for you.

    final Comparator<Map.Entry<String, Integer>> byMatchesWon = 
            Comparator.comparing(Map.Entry::getValue, Comparator.reverseOrder());
    final Comparator<Map.Entry<String, Integer>> byTeamName = 
            Comparator.comparing(Map.Entry::getKey);

    final List<String> hasToBeReturned = matchesWonByTeam
            .entrySet().stream()
            .sorted(byMatchesWon.thenComparing(byTeamName))
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());

Note - inlining comparators would not work here, compiler will not be able to infer the proper implementation.

harshtuna
  • 757
  • 5
  • 14
  • You can usually inline the comparators by providing a type witness or an explicit type for one of the lambda arguments. – Stuart Marks Feb 25 '15 at 15:16
3

You could do it that way using functional programming :

final Map<String, Integer> map = new HashMap<>();
map.put("test", 1);
map.put("test1", 3);
map.put("test3", 4);
map.put("test2", 75);
map.put("a", 75);
map.put("test100", 100);

final List<String> test = map
        .entrySet()
        .stream()
        .sorted((Entry<String, Integer> o1, Entry<String, Integer> o2) -> {
              return o1.getValue().equals(o2.getValue()) ? 
                          o1.getKey().compareTo(o2.getKey()) 
                              : o1.getValue().compareTo(o2.getValue());
          })
        .map(e -> e.getKey())
        .collect(Collectors.toList());

for(String s : test)
      System.out.println(s); 

This example would output

test test1 test3 a test2 test100

Jean-François Savard
  • 20,626
  • 7
  • 49
  • 76
0

Return the entry set, make a List, then use an anonymous Comparator implementation to sort the entries.

List<Entry<String,Integer>> matchesWonList = new ArrayList<Entry<String,Integer>>(matchesWonByTeam.entrySet());
Collections.sort(matchesWonList , new   Comparator<Entry<String,Integer>>(){
    //implement your comparator here.
});
aglassman
  • 2,643
  • 1
  • 17
  • 30
0

This works:

Map<String,Integer> map = new HashMap<String,Integer>();
/*...fill map...*/

SortedSet<Map.Entry<String, Integer>> sortedSet = new TreeSet<>(new Comparator<Map.Entry<String, Integer>>() {
    @Override
    public int compare(Entry<String, Integer> e1, Entry<String, Integer> e2) {
        int res = e1.getValue().compareTo(e2.getValue());
        if(res == 0)
            return e1.getKey().compareTo(e2.getKey());
        return res * -1;
    }
});
sortedSet.addAll(map.entrySet());

List<String> list = new ArrayList<>();
for(Map.Entry<String, Integer> e: sortedSet)
    list.add(e.getKey());

This is assuming you want the order to be from largest Integer to smallest Integer. If not, remove the * -1 when returning res.

dbank
  • 1,173
  • 1
  • 17
  • 29
0

matchesWonByTeam now will be a linkedHashMap which maintains the order.

matchesWonByTeam = matchesWonByTeam.entrySet()
                .stream()
                .sorted(
                        new Comparator<Map.Entry<String, Integer>>() {
                            @Override
                            public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {

                                if(o1.getValue() < o2.getValue()) {
                                    return  -1;
                                }
                                if(o1.getValue() > o2.getValue()) {
                                    return 1;
                                }
                                return o1.getKey().compareTo(o2.getKey());

                            }
                        }
                )
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1,e2) -> e1, LinkedHashMap::new));
vishal ms
  • 44
  • 3