Home > Software design >  Collect list of objects to set of strings after groupingBy java stream
Collect list of objects to set of strings after groupingBy java stream

Time:07-17

Given the following classes Order and Item and a list of Orders

@Getter
@AllArgsConstructor
@ToString
public class Order {
    String customerName;
    List<Item> items;
}

@Getter
@AllArgsConstructor
@ToString
@EqualsAndHashCode
public class Item {
    long id;
    String name;
}

I need to create a map Map<String,Set<String>> itemsByCustomerName where keys are customer names from Order and a set of names of all Items belonging to the customer name.

Example input:

List<Order> orders = List.of(
        new Order("John", List.of(new Item(1, "A"), new Item(2, "B"), new Item(3, "C"))),
        new Order("Alex", List.of(new Item(1, "A"), new Item(8, "H"), new Item(11, "K"))),
        new Order("John", List.of(new Item(1, "A"), new Item(6, "F"), new Item(7, "G"))),
        new Order("Alex", List.of(new Item(1, "A"), new Item(8, "H"), new Item(12, "L"))),
        new Order("Dave", List.of(new Item(24,"X"), new Item(25,"Y"), new Item(26, "Z"))));

the desired output would be

{Alex=[A, H, K, L], John=[A, B, C, F, G], Dave=[X, Y, Z]}

I have tried many ways including my last attempt below, but getting compile errors

Map<String, Set<String>> itemsByCustomerName =
    orders.stream().collect(groupingBy(
            Order::getCustomerName,
            mapping(order -> order.getItems().stream().map(Item::getName), toSet())));

Error:

Required type:
Map<String, Set<String>>
Provided:
Map<String, Set<Object>>

no instance(s) of type variable(s) R exist so that Stream<R> conforms to String inference variable T 
has incompatible bounds: equality constraints: String lower bounds: Stream<R81591>

How can I get instead of just a map of orders by name:

Map<String, List<Order>> ordersByName =
    orders.stream().collect(groupingBy(Order::getCustomerName));

to a Map<String, Set<Item>> or much better Map<String, Set<String>> with a set of item names?

Generally asking: how to convert list of orders to set of strings after groupingBy?

CodePudding user response:

You were very close.

Since you need to transform a stream element not into a single object, but extract a collection of items from the order, you need a different collector - flatMapping() instead of mapping().

Map<String, Set<String>> itemsByCustomerName =
    orders.stream().collect(Collectors.groupingBy(
        Order::getCustomerName,
        Collectors.flatMapping(order -> order.getItems().stream().map(Item::getName),
            Collectors.toSet())));

CodePudding user response:

Collectors.groupingBy(Order::getCustomerName, Collectors.toSet()) should work in this case. The second parameter here is the collector used by groupingBy internally.

  • Related