11.6 Quais são os produtos de cada cliente?

Objetivo: Obter um Map> associando cada cliente à lista total de produtos comprados. Abordagem inicial: Agrupando por cliente Map customerToPayments = payments.stream() .collect(Collectors.groupingBy(Payment::getCustomer)); Porém, queremos produtos, não pagamentos. Tentativa 1: Mapeando diretamente os produtos Resultado intermediário com listas aninhadas: Map customerToProductsList = payments.stream() .collect(Collectors.groupingBy( Payment::getCustomer, Collectors.mapping(Payment::getProducts, Collectors.toList()) )); Saída contém List>, o que não é o desejado. Solução com duas etapas: Flatten com flatMap Achatar as listas aninhadas usando flatMap: Map customerToProducts2steps = customerToProductsList.entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().stream() .flatMap(List::stream) .collect(Collectors.toList()) )); Solução em uma única etapa (menos legível) Mesma ideia, mas com tudo encadeado: Map customerToProducts1step = payments.stream() .collect(Collectors.groupingBy(Payment::getCustomer, Collectors.mapping(Payment::getProducts, Collectors.toList()))) .entrySet().stream() .collect(Collectors.toMap( Map.Entry::getKey, e -> e.getValue().stream() .flatMap(List::stream) .collect(Collectors.toList()) )); Desvantagem: Código difícil de entender. Solução alternativa com Collectors.reducing Usando reducing para acumular listas de produtos: Map customerToProducts = payments.stream() .collect(Collectors.groupingBy(Payment::getCustomer, Collectors.reducing( Collections.emptyList(), Payment::getProducts, (l1, l2) -> { List l = new ArrayList(); l.addAll(l1); l.addAll(l2); return l; } ) )); Observação: Não existe um método auxiliar no Java para unir listas diretamente, o que exige escrever o BinaryOperator manualmente. Exemplo: ProdutosPorClienteExemplo.java

Apr 15, 2025 - 02:39
 0
11.6 Quais são os produtos de cada cliente?

Objetivo: Obter um Map> associando cada cliente à lista total de produtos comprados.

Abordagem inicial: Agrupando por cliente

Map> customerToPayments =
payments.stream()
.collect(Collectors.groupingBy(Payment::getCustomer));

Porém, queremos produtos, não pagamentos.

Tentativa 1: Mapeando diretamente os produtos

Resultado intermediário com listas aninhadas:

Map>> customerToProductsList =
payments.stream()
.collect(Collectors.groupingBy(
Payment::getCustomer,
Collectors.mapping(Payment::getProducts, Collectors.toList())
));

Saída contém List>, o que não é o desejado.

Solução com duas etapas: Flatten com flatMap

Achatar as listas aninhadas usando flatMap:

Map> customerToProducts2steps =
customerToProductsList.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().stream()
.flatMap(List::stream)
.collect(Collectors.toList())
));

Solução em uma única etapa (menos legível)

Mesma ideia, mas com tudo encadeado:

Map> customerToProducts1step = payments.stream()
.collect(Collectors.groupingBy(Payment::getCustomer,
Collectors.mapping(Payment::getProducts, Collectors.toList())))
.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().stream()
.flatMap(List::stream)
.collect(Collectors.toList())
));

Desvantagem: Código difícil de entender.

Solução alternativa com Collectors.reducing

Usando reducing para acumular listas de produtos:

Map> customerToProducts = payments.stream()
.collect(Collectors.groupingBy(Payment::getCustomer,
Collectors.reducing(
Collections.emptyList(),
Payment::getProducts,
(l1, l2) -> {
List l = new ArrayList<>();
l.addAll(l1);
l.addAll(l2);
return l;
}
)
));

Observação: Não existe um método auxiliar no Java para unir listas diretamente, o que exige escrever o BinaryOperator manualmente.

Exemplo: ProdutosPorClienteExemplo.java