6

I have written the word program in Java, and have come up with the list of words and frequencies. The result is currently stored in LinkedHashMap. The results look something like below:

garden-->2
road-->4
street-->5
park-->5
highway-->5

In the above result set, stored in LinkedHashMap, how can I sort it to only sort the keys which have the same frequency. We still want to maintain the order of frequency as given.

the result would look something like:

garden-->2
road-->4
highway-->5
park-->5
street-->5

Thank You.

ASutherland
  • 77
  • 1
  • 8
omi
  • 81
  • 1
  • 1
  • 5
  • `data.entrySet().stream().sorted(Comparator.comparing(Entry::getValue).thenCompartring(Comparator.comparing(Entry::getKey).collect(Collectors.toMap(Entry::getKey, Entry::getValue, mergeFunction, LinkedHashMap::new))`. – Boris the Spider Feb 03 '18 at 16:54

2 Answers2

2

I was able to accomplish this similarly to Boris' suggested answer. However, any IDE that I used refused to infer the generic types, so I had to explicitly specify them for the first call to Comparator#comparing as seen below:

Map<String, Integer> map = new LinkedHashMap<>();

map.put("garden", 2);
map.put("road", 4);
map.put("street", 5);
map.put("park", 5);
map.put("highway", 5);

map = map.entrySet()
         .stream()
         .sorted(Comparator.<Entry<String, Integer>, Integer>comparing(Entry::getValue)
                           .thenComparing(Comparator.comparing(Entry::getKey)))
         .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (k, v) -> {
             throw new IllegalStateException(String.format("Duplicate Key: %s", k));
         }, LinkedHashMap::new));

System.out.println(map);

The code above yields the following output:

{garden=2, road=4, highway=5, park=5, street=5}

I've noticed that you wish for the values to be in descending order, but the keys which share a value to be in ascending order. Below is that solution (which is nearly identical):

map = map.entrySet()
         .stream()
         .sorted(Comparator.<Entry<String, Integer>, Integer>comparing(Map.Entry::getValue).reversed()
                           .thenComparing(Comparator.comparing(Entry::getKey)))
         .collect(Collectors.toMap(Entry::getKey, Entry::getValue, (k, v) -> {
                throw new IllegalStateException(String.format("Duplicate key %s", k));
         }, LinkedHashMap::new));

Note: Entry refers to java.util.Map.Entry and Collectors refers to java.util.stream.Collectors.

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
  • 1
    Thank You Very Much, what does Collectors refer to ? – omi Feb 03 '18 at 17:44
  • 1
    Nice answer. I could only solve by creating two explicit comparators (c1,c2) and using sorted(c1.thenComparing(c2)). When you include the generics it starts working. Still not sure why I couldn't chain together .thenComparing() without this. You have my vote. – Ian Mc Feb 03 '18 at 17:45
  • @AnujKumar `Collectors` refers to `java.util.stream.Collectors` – Jacob G. Feb 03 '18 at 17:45
  • Thank You, when i run the code it says cannot find Symbol Reference for Collectors. It is strange, any clue why would it give that error. – omi Feb 03 '18 at 17:47
  • @AnujKumar Are you using an IDE (Intellij, Eclipse, etc.)? My guess is that it's just a typo somewhere, as it works perfectly for me. Read this: https://stackoverflow.com/questions/25706216/what-does-a-cannot-find-symbol-compilation-error-mean Could you possibly be compiling with Java 7 or below? – Jacob G. Feb 03 '18 at 17:49
  • Oh, your example shows the sorted `LinkedHashMap` with ascending values. And `disambiguation` **does** come before `state` in what you just posted. – Jacob G. Feb 03 '18 at 17:56
  • First Sort has to be on Values(descending & data is in that order), so List would be first word on top of output, do you get List as the top item ? Once on values then on the keys which have the same values(asending order) – omi Feb 03 '18 at 17:59
  • @AnujKumar I've fixed it by adding a call to Comparator#reversed after the first call to Comparator#comparing. I've just edited my answer with the modified solution. – Jacob G. Feb 03 '18 at 18:06
  • 1
    Thanks Jacob. i think it works now, I will run some test. Appreciate your help! – omi Feb 03 '18 at 18:08
1

If you are looking in JAVA7 or below, following simple code can do your work.

Map<String, Integer> map = new LinkedHashMap<>();

map.put("garden", 2);
map.put("road", 4);
map.put("street", 5);
map.put("park", 5);
map.put("highway", 5);

List<Entry<String, Integer>> list = new ArrayList<>();
list.addAll(map.entrySet());

Collections.sort(list, new Comparator<Entry<String, Integer>>() {

    @Override
    public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
        return o1.getValue()-o2.getValue() != 0 ?  o1.getValue()-o2.getValue() : o1.getKey().compareTo(o2.getKey());
    }
});
System.out.println(list);

Output:-

[garden=2, road=4, highway=5, park=5, street=5]

I guess, the code implemented by Jacob is doing the same job here.

nagendra547
  • 5,672
  • 3
  • 29
  • 43
  • Thank You all for responding, it was a great help and the solutions given above worked! You guys are stars !!! – omi Feb 03 '18 at 23:20