2

I am trying to get product reviews Map based on their name and need a map like

Map<String, Set<String>> productReviewMap;

but when I try to get the map I am getting

Map<String, Set<Set<String>>> productReviewMap

based on following code :

Map<String, Set<Set<String>>> productReviewMap = products.stream().collect(
                    Collectors.groupingBy(Product::getName, Collectors.mapping(Product::getReviews, Collectors.toSet())));

How I can get the expected map. We use flatMap in streams but how can I achieve it in collectors ?

Jacob G.
  • 28,856
  • 5
  • 62
  • 116
Devendra
  • 1,864
  • 6
  • 29
  • 49
  • 1
    If you were using Java 9+, I'd opt for [`Collectors#flatMapping`](https://docs.oracle.com/javase/10/docs/api/java/util/stream/Collectors.html#flatMapping(java.util.function.Function,java.util.stream.Collector)) – Jacob G. Nov 11 '18 at 20:52
  • 1
    You can use `toMap` collector with merge function. so in merge function merge lists or sets. – Hadi J Nov 11 '18 at 20:54
  • @JacobG thanks, I am using java 8. will use toMap – Devendra Nov 11 '18 at 20:57
  • `products.stream() .collect(Collectors.toMap(Product::getName,v->new HashSet<>(v.getReviews()),(v1,v2)->{v1.addAll(v2);return v1;}));` – Hadi J Nov 11 '18 at 21:08

3 Answers3

5

There's no built-in collector for this is JDK8, so your options are limited:

Use toMap:

Map<String, Set<String>> resultSet = 
        products.stream()
                .collect(toMap(Product::getName,
                        p -> new HashSet<>(p.getReviews()),
                        (l, r) -> {
                            l.addAll(r);
                            return l;
                        }));

or use a custom collector. see here and the last code snippet here

JDK9 has flatMapping and can be used as follows:

either this:

 Map<String, Set<String>> resultSet = 
        products.stream()
                .collect(groupingBy(Product::getName,
                        mapping(Product::getReviews,
                                flatMapping(Collection::stream,
                                        toSet()))));

or this:

Map<String, Set<String>> resultSet = 
       products.stream()
               .collect(groupingBy(Product::getName,
                        flatMapping(s -> s.getReviews().stream(),toSet())));
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
0

Try this . this would work.
Assuming you are using java 8.

Map<String,Set<String>> reviewMap = products.stream().collect(Collectors.toMap(Product::getName,Product::getReviews));
Mr Nobody
  • 388
  • 4
  • 11
-1

What are the "products" in your code ?

I made a simple example where products are simply an arrayList, and it works like you want. (i haven implemented a "product" class, so it is simply p -> p

List<String> products = new ArrayList<>();
Map<String, Set<String>> productReviewMap = new HashMap<>();
final Map<String, Set<String>> collect = products.stream()
  .collect(Collectors.groupingBy(p -> p, Collectors.mapping(p -> p, Collectors.toSet())));