priya priya - 4 years ago 715
Java Question

How to sort hash map based on number of keys for a value using flatmap java8?

This is a follow-up of How to get the count of keys for values in a hash map using lambda. I have a

HashMap
and I want to find the number of keys for each value

Map<Integer, List<Integer>> map = new HashMap<Integer, List<Integer>>() {{
put(0, Arrays.asList(1, 2));
put(1, Arrays.asList(2, 0, 3));
put(2, Arrays.asList(4,0,1));
put(3, Arrays.asList(4,1, 5));
put(4, Arrays.asList(5,2,3));
put(5, Arrays.asList(4,3));
}};


According to the above post, I tried flat mapping:

Map<Object, Long> ex =
map.values()
.stream()
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(v -> v, Collectors.counting()));

System.out.println(ex);


The output is

{0=2, 1=3, 2=3, 3=3, 4=3, 5=2}.


This means 0 has two keys, 1 has three keys and so on. Now I want to sort the keys and values in descending order based on count of keys. I tried something like this:

Map<Object, Long> ex =
map.values()
.stream()
.flatMap(Collection::stream)
.collect(Collectors.groupingBy(v -> v, Collectors.counting()));

.entrySet()
.stream()
.sorted(Map.Entry.<String, Long>comparingByValue(reverseOrder()).thenComparing(Map.Entry.comparingByKey()))
.collect(LinkedHashMap::new, (m,e) -> m.put(e.getKey(), e.getValue()), Map::putAll);


I want the following output:

1=[2, 3, 0], 2=[1,4,0], 3=[1, 4, 5], 4=[2, 3, 5], 0=[1, 2], 5=[3, 4]


The keys and values should be arranged in descending according to this count of keys
{0=2, 1=3, 2=3, 3=3, 4=3, 5=2}
: 1, 2, 3, 4 has three keys, 0 and 5 have two keys.

For example:
1=[2, 3, 0]
: 1 has three keys so it appears first with
[2, 3, 0]
: 2 and 3 have three keys and 0 has only two keys.

Answer Source

You could have the following:

Map<Integer, List<Integer>> sorted = 
    map.entrySet()
       .stream()
       .sorted(comparing(e -> ex.get(e.getKey()), reverseOrder()))
       .collect(toMap(
           Map.Entry::getKey,
           e -> e.getValue().stream().sorted(comparing(ex::get, reverseOrder())).collect(toList()),
           (v1, v2) -> { throw new IllegalStateException(); },
           LinkedHashMap::new
       ));

This creates a Stream of the entries of the map, sorts them in reverse order according the count of keys for that entry's key and finally collects that into a map where the new value is sorted in reverse order with regard to the count of each integer (ex::get). The collecting map is a LinkedHashMap to preserve encounter order.

Output:

{1=[2, 3, 0], 2=[4, 1, 0], 3=[4, 1, 5], 4=[2, 3, 5], 0=[1, 2], 5=[4, 3]}

Static imports used:

import static java.util.Comparator.comparing;
import static java.util.Comparator.reverseOrder;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;

You won't be able to use a TreeMap with a custom comparator because it sorts knowing the key alone and not knowing the entire entry.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download