简体   繁体   中英

Java-Stream - Collect a List of objects into a Set of Strings after applying Collector groupingBy

Given the following classes Order and Item and a list of Order s.

@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 Item s belonging to the customer name.

Input example:

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?

So, my question is: how to convert a list of orders into a set of item names after applying groupingBy ?

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())));

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM