Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8- Multiple Group by Into Map of Collection

I'm trying to do a groupingBy on two attributes of an object with Java streams. That's easy enough as has been documented by some answers:

products.stream().collect(
        Collectors.groupingBy(Product::getUpc, 
        Collectors.groupingBy(Product::getChannelIdentifier)));

for example, the above snippet will produce a Map of Maps in the form

Map<String, Map<String, List<Product>>>

Where a map has keys of UPC codes and its values are maps that have keys of Channel Identifiers which reference a list of products.

That's cool, but what if I don't need the nested value to be a map? That is to say, I want to organize the nested collection by ChannelIdentifier, but I only care about the .values() of the map, not the map itself. Is there a way to get a result that matches the following?

Map<String, List<List<Product>>

Lists or collections... it doesn't matter. Thanks!

like image 426
IcedDante Avatar asked Oct 29 '15 21:10

IcedDante


1 Answers

The grouping operation unavoidably needs to maintain a Map as it has to track the key values for the grouping. But you can use the values() view directly:

Map<String, Collection<List<Product>>> m=products.stream().collect(
    Collectors.groupingBy(Product::getUpc, Collectors.collectingAndThen(
        Collectors.groupingBy(Product::getChannelIdentifier), Map::values)));

If the resulting map will have a longer lifetime and you want to reduce the required storage space, or if you need a List, you may copy the view into a list during that step:

Map<String, List<List<Product>>> map=products.stream().collect(
    Collectors.groupingBy(Product::getUpc, Collectors.collectingAndThen(
        Collectors.groupingBy(Product::getChannelIdentifier),
        m -> new ArrayList<>(m.values()) )));
like image 68
Holger Avatar answered Sep 27 '22 19:09

Holger