Java流:使用groupingBy而不是列表时如何映射到单个项目

bbK*_*ing 1 java java-stream

给定一个订单类,例如:

@ToString
@AllArgsConstructor
@Getter
static class Order {
    long customerId;
    LocalDate orderDate;
}
Run Code Online (Sandbox Code Playgroud)

和订单列表:

List<Order> orderList = List.of(new Order(1, LocalDate.of(2020,Month.APRIL,21)),
                                new Order(1, LocalDate.of(2021,Month.APRIL,21)),
                                new Order(1, LocalDate.of(2022,Month.APRIL,21)),
                                new Order(2, LocalDate.of(2020,Month.APRIL,21)),
                                new Order(2, LocalDate.of(2021,Month.APRIL,21)),
                                new Order(3, LocalDate.of(2020,Month.APRIL,21)),
                                new Order(3, LocalDate.of(2022,Month.APRIL,21)),
                                new Order(4, LocalDate.of(2020,Month.APRIL,21)));
Run Code Online (Sandbox Code Playgroud)

我需要获得一份清单,customerId其中列出了最后一次orderDate超过 6 个月的情况。所以对于上面的例子[2,4]。我的想法是首先按 分组customerId,第二个地图到最后orderDate,第三个过滤那些超过 6 个月的地图。我陷入了如何将最近的订单映射到单个订单的第二步orderDate

第一步

Map<Long, List<Order>> grouped =
        orderList.stream()
                .collect(Collectors.groupingBy(Order::getCustomerId));
Run Code Online (Sandbox Code Playgroud)

第二步(卡在这里如何更改上述内容以仅获取一项作为值)

Map<Long, Order> grouped =
        orderList.stream()
                .collect(Collectors.groupingBy(Order::getCustomerId, ???));
Run Code Online (Sandbox Code Playgroud)

甚至更好

Map<Long, LocalDate> grouped =
        orderList.stream()
                .collect(Collectors.groupingBy(Order::getCustomerId, ???));
Run Code Online (Sandbox Code Playgroud)

我尝试过使用Collectors.mapping()Collectors.reducing()Collectors.maxBy()有很多编译错误。

Bru*_*noT 7

使用Collectors.toMap收集器获取按客户 ID 列出的订单的地图。之后,您可以仅过滤 6 个月以上的订单。

参见下面的实现:

import java.time.LocalDate;
import java.time.chrono.ChronoLocalDate;
import java.util.List;
import java.util.Optional;
import java.util.Collections;
import java.util.Objects;
import java.util.Comparator;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.stream.Collectors;
Run Code Online (Sandbox Code Playgroud)
public static List<Long> getCustomerIdsOfOrdersOlderThanSixMonths(final List<Order> orderList) {
    return Optional.ofNullable(orderList)
            .orElse(Collections.emptyList())
            .stream()
            .filter(o -> Objects.nonNull(o) && Objects.nonNull(o.getOrderDate()))
            .collect(Collectors.toMap(
                  Order::getCustomerId,
                  Function.identity(),
                  BinaryOperator.maxBy(Comparator.comparing(Order::getOrderDate))))
            .values()
            .stream()
            .filter(o -> o.getOrderDate()
                  .plusMonths(6)
                  .isBefore(ChronoLocalDate.from(LocalDate.now())))
            .map(Order::getCustomerId)
            .collect(Collectors.toList());
    }
}
Run Code Online (Sandbox Code Playgroud)
List<Long> customerIds = getCustomerIdsOfOrdersOlderThanSixMonths(orderList);
// [2, 4]
Run Code Online (Sandbox Code Playgroud)