Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collectors.groupby for Map<String,List<String>

Forgive me if the solution is very obvious but I can't seem to figure out how to do this

public static void main(String[] args) {
    Map<String, String> map = new HashMap<>();
    map.put("b1", "a1");
    map.put("b2", "a2");
    map.put("b3", "a1");
    Map<String, List<String>> mm = map.values().stream().collect(Collectors.groupingBy(m -> m));
    System.out.println(mm);
}

I want to group by based on values in hashmap. I want the output to be {a1=[b1, b3], a2=[b2]} but it is currently coming as {a1=[a1, a1], a2=[a2]}

like image 696
Ashishkumar Singh Avatar asked Dec 31 '18 11:12

Ashishkumar Singh


People also ask

How do you use groupingBy collectors?

The groupingBy() method of Collectors class in Java are used for grouping objects by some property and storing results in a Map instance. In order to use it, we always need to specify a property by which the grouping would be performed. This method provides similar functionality to SQL's GROUP BY clause.

How does Groupby work in Java 8?

In Java 8, you retrieve the stream from the list and use a Collector to group them in one line of code. It's as simple as passing the grouping condition to the collector and it is complete. By simply modifying the grouping condition, you can create multiple groups.

Can we use stream with map in Java?

Converting only the Value of the Map<Key, Value> into Stream: This can be done with the help of Map. values() method which returns a Set view of the values contained in this map. In Java 8, this returned set can be easily converted into a Stream of key-value pairs using Set. stream() method.

What is collectors in Java?

Collectors is a final class that extends Object class. It provides reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc. Java Collectors class provides various methods to deal with elements. Methods.


2 Answers

Currently, you're streaming over the map values (which I assume is a typo), based on your required output you should stream over the map entrySet and use groupingBy based on the map value's and mapping as a downstream collector based on the map key's:

 Map<String, List<String>> result = map.entrySet()
            .stream()
            .collect(Collectors.groupingBy(Map.Entry::getValue,
                          Collectors.mapping(Map.Entry::getKey, 
                                        Collectors.toList())));

You could also perform this logic without a stream via forEach + computeIfAbsent:

Map<String, List<String>> result = new HashMap<>();
map.forEach((k, v) -> result.computeIfAbsent(v, x -> new ArrayList<>()).add(k));
like image 79
Ousmane D. Avatar answered Oct 14 '22 20:10

Ousmane D.


You can use Collectors.mapping with Collectors.groupingBy on the entrySet of the map as :

Map<String, List<String>> mm = map.entrySet()
        .stream()
        .collect(Collectors.groupingBy(Map.Entry::getValue, 
                Collectors.mapping(Map.Entry::getKey, Collectors.toList())));

but it is currently coming as {a1=[a1, a1], a2=[a2]}

That's because you are currently grouping on the values collection which is {a1, a2, a1} only.

like image 42
Naman Avatar answered Oct 14 '22 18:10

Naman