Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 streams, convert List of object to Map<String, Set<String>>

I have already gone through few examples and those did not work for me.

Here is what I am trying to do:

I have a List<SomeClass> of the following class:

class SomeClass {
  String rid;
  String name;
  ...
}

The values in my List look like this:

SomeClass(1,"apple")
SomeClass(1,"banana")
SomeClass(1,"orange")
SomeClass(2,"papaya")
SomeClass(2,"peaches")
SomeClass(3,"melons")

I want to convert the above List into a Map<String, Set<String>>, where key is rid and value is Set of name field.

To solve this using Java Streams I am using groupingBy and I could come to below solution:

someClassList
            .stream()
            .map(SomeClass::getName)
            .collect(
                  Collectors.groupingBy(
                      SomeClass::getRid, Collectors.toSet()));

But this gives me compilation error. How do I solve this and what is the problem with my approach?

like image 698
Bikas Katwal Avatar asked Jul 17 '18 05:07

Bikas Katwal


People also ask

How will you convert a List into Map using streams in Java 8?

With Java 8, you can convert a List to Map in one line using the stream() and Collectors. toMap() utility methods. The Collectors. toMap() method collects a stream as a Map and uses its arguments to decide what key/value to use.

How do you convert a List of objects into a stream of objects?

Converting a list to stream is very simple. As List extends the Collection interface, we can use the Collection. stream() method that returns a sequential stream of elements in the list.

Which method will be used to convert the collection objects into stream object in java8?

stream(). mapToInt(AClass::getValue).


2 Answers

When you call .map(SomeClass::getName) on your Stream<SomeClass>, you get a Stream<String>. You can't execute collect(Collectors.groupingBy(SomeClass::getRid,...)) on a Stream<String> (you can only execute it on a Stream<SomeClass>). Therefore your map step is wrong.

You need to pass the Collector returned by Collectors.mapping() to Collectors.groupingBy() in order to map the SomeClass instances to Strings after they are grouped by getRid.

Map<String, Set<String>> map =
    someClassList.stream()
                 .collect(Collectors.groupingBy(SomeClass::getRid, 
                                                Collectors.mapping(SomeClass::getName,
                                                                   Collectors.toSet())));
like image 174
Eran Avatar answered Oct 28 '22 06:10

Eran


Although not as readable as the groupingBy collector; you can use the toMap collector just as well:

myList.stream()
      .collect(toMap(SomeClass::getRid, e -> new HashSet<>(singleton(e.getName())), 
                 (l, r) -> {l.addAll(r); return l;}));

Ensure that you have the necessary imports for singleton and toMap or you can just use Collectors.toMap(...) and Collections.singleton(...) respectively.

like image 32
Ousmane D. Avatar answered Oct 28 '22 07:10

Ousmane D.