Nuestro equipo redactor ha estado largas horas buscando para dar espuestas a tus preguntas, te brindamos la respuesta así que nuestro objetivo es resultarte de gran ayuda.
Solución:
¿Hay alguna forma de resolver la tarea anterior en una secuencia?
Depende de lo que quieras decir con “en una secuencia”. Desea realizar una operación de reducción que probablemente se caracterice mejor como una combinación de una secuencia de reducciones:
- agrupar los pedidos por mes
- dentro de cada grupo mensual, agregue los pedidos de cada cliente para obtener una cantidad total
- entre cada grupo mensual de resultados agregados por cliente, elija el de mayor monto (nota: no bien definido en caso de empate)
Desde la perspectiva de la API de flujo, realizar cualquiera de esas reducciones individuales en un flujo es una operación de terminal en ese flujo. Puede procesar el resultado con una nueva secuencia, incluso encadenándola sintácticamente, pero aunque eso podría tomar la forma sintáctica de una sola cadena de invocaciones de métodos, no constituiría todas las operaciones que suceden en una sola secuencia.
También puede crear un único Collector
(o los componentes de uno) para que obtenga el resultado directamente recopilando el flujo de sus elementos de entrada, pero internamente, ese recopilador aún necesitaría realizar las reducciones individuales, ya sea creando y consumiendo secuencias adicionales internamente, o realizando las mismas tareas a través de API que no son de secuencia. Si cuenta esas operaciones internas, nuevamente, no, no constituiría realizar operaciones en una sola secuencia. (Pero si no considera esas reducciones internas, entonces sí, esto lo hace todo en una sola transmisión).
Intenta usar groupingBy
, summingLong
y comparingLong
como se muestra a continuación
Map topBuyers = orders.stream()
.collect(Collectors.groupingBy(Order::getOrderMonth,
Collectors.groupingBy(Order::getCustomer,
Collectors.summingLong(Order::getAmount))))
.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey,
order -> order.getValue().entrySet().stream()
.max(Comparator.comparingLong(Map.Entry::getValue))
.map(cust -> new BuyerDetails(cust.getKey(), cust.getValue())).get()));
Producción
"MARCH": "customer": "Dan", "amount": 300 ,
"APRIL": "customer": "Jenny", "amount": 550
Tiene un flujo anidado, por lo que no es un flujo y devuelve Map
.
orders.stream()
.collect(
Collectors.groupingBy(Order::getOrderMonth,
Collectors.collectingAndThen(
Collectors.groupingBy(
Order::getCustomer,
Collectors.summarizingLong(Order::getAmount)
),
e -> e.entrySet()
.stream()
.map(entry -> new BuyerDetails(entry.getKey(), entry.getValue().getSum()))
.max(Comparator.comparingLong(BuyerDetails::getAmount))
)
)
)
entonces hay 3 pasos:
- Agrupar por mes
Collectors.groupingBy(Order::getOrderMonth,
- Agrupar por nombre de cliente y sumar el monto total del pedido
Collectors.groupingBy(Order::getCustomer, Collectors.summarizingLong( Order::getAmount))
- filtrando el resultado intermedio y dejando solo a los clientes con la cantidad máxima
max(Comparator.comparingLong(BuyerDetails::getAmount))
la salida es
APRIL = Optional [ BuyerDetails customer = 'Jenny', amount = 550 ],
MARCH = Optional [ BuyerDetails customer = 'Dan', amount = 300 ]
También tengo curiosidad por saber si esto se puede hacer sin flujo adicional.
Te invitamos a añadir valor a nuestra información tributando tu experiencia en las explicaciones.