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
?
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.