Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Collect results of a map operation in a Map using Collectors.toMap or groupingBy

I've got a list of type List<A> and with map operation getting a collective list of type List<B> for all A elements merged in one list.

List<A> listofA = [A1, A2, A3, A4, A5, ...]

List<B> listofB = listofA.stream()
  .map(a -> repo.getListofB(a))
  .flatMap(Collection::stream)
  .collect(Collectors.toList());

without flatmap

List<List<B>> listOflistofB = listofA.stream()
  .map(a -> repo.getListofB(a))
  .collect(Collectors.toList());

I want to collect the results as a map of type Map<A, List<B>> and so far trying with various Collectors.toMap or Collectors.groupingBy options but not able to get the desired result.

like image 447
Amitoj Avatar asked Oct 02 '19 14:10

Amitoj


People also ask

What is Collectors groupingBy?

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 do you collect on a map?

Method 1: Using Collectors.toMap() Function The Collectors. toMap() method takes two parameters as the input: KeyMapper: This function is used for extracting keys of the Map from stream value. ValueMapper: This function used for extracting the values of the map for the given key.

How do Map collectors work?

The toMap() method is a static method of Collectors class which returns a Collector that accumulates elements into a Map whose keys and values are the result of applying the provided mapping functions to the input elements.

What is the use of collectors in Java?

Class Collectors. Implementations of Collector that implement various useful reduction operations, such as accumulating elements into collections, summarizing elements according to various criteria, etc.


2 Answers

You can use the toMap collector with a bounded method reference to get what you need. Also notice that this solution assumes you don't have repeated A instances in your source container. If that precondition holds this solution would give you the desired result. Here's how it looks.

Map<A, Collection<B>> resultMap = listofA.stream()
    .collect(Collectors.toMap(Function.identity(), repo::getListofB);

If you have duplicate A elements, then you have to use this merge function in addition to what is given above. The merge function deals with key conflicts if any.

Map<A, Collection<B>> resultMap = listofA.stream()
       .collect(Collectors.toMap(Function.identity(), repo::getListofB, 
            (a, b) -> {
                a.addAll(b);
                return a;
        }));

And here's a much more succinct Java9 approach which uses the flatMapping collector to handle repeated A elements.

Map<A, List<B>> aToBmap = listofA.stream()
        .collect(Collectors.groupingBy(Function.identity(),
                Collectors.flatMapping(a -> getListofB(a).stream(), 
                        Collectors.toList())));
like image 187
Ravindra Ranwala Avatar answered Oct 10 '22 11:10

Ravindra Ranwala


It would be straight forward,

listofA.stream().collect(toMap(Function.identity(), a -> getListofB(a)));
like image 2
Vikas Yadav Avatar answered Oct 10 '22 10:10

Vikas Yadav