3

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.

Community
  • 1
  • 1
priya
  • 375
  • 5
  • 22
  • Have a check at : http://stackoverflow.com/questions/109383/sort-a-mapkey-value-by-values-java, basically use a treemap and a comparator – Louis F. Jan 03 '16 at 11:21
  • @LouisF. Yeah I checked. if i use comparator, I can get the following ouput, {1=3, 2=3, 3=3, 4=3, 0=2, 5=2}. but what I want is 1=[2, 3, 0], 2=[1,4,0], 3=[1, 4, 5], 4=[2, 3, 5], 0=[1, 2], 5=[3, 4]. So is there any predefined function to sort based on count of keys of a value in java8 using streams? – priya Jan 03 '16 at 12:01
  • I am very new to java 8. So really don't know how to perform. Any ideas? – priya Jan 03 '16 at 12:06
  • 1
    Here you want to sort both keys and the value lists. First sort the keys using TreeMap and custom comparator. Then try to sort each value list. Don't try to mix everything even if you can, this will hurt readability. – Mrinal Jan 03 '16 at 12:27

1 Answers1

4

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;
Tunaki
  • 132,869
  • 46
  • 340
  • 423