如何将多个集合的结构展平为一个具有通用 ID 和流的集合

How to flatten the structure of multiple collections into a single one with a common id with streams

假设我有一个 dto 列表,例如:

@Builder(setterPrefix = "with")
@Data
public class ListWithDetailsRow {
    String name;
    LocalDateTime updatedAt;
    LocalDateTime createdAt;
    String customerId;
    String listId;
    String productName;
    String productId;
    Integer quantity;
    LocalDateTime addedAt;
}

我想将上面的映射到:

@Builder
@Getter
@Setter
@RequiredArgsConstructor
public class ListDetails {
    private final String name;
    private final String listId;
    private final String customerId;
    private final LocalDateTime createdAt;
    private final LocalDateTime updatedAt;
    private final List<ListProductDetails> products;
}

其中 ListProductDetails 看起来像:

@RequiredArgsConstructor
@Builder
@Getter
@Setter
public class ListProductDetails {
    private final String productId;
    private final Integer quantity;
    private final LocalDateTime addedAt;
}

到目前为止我有:

public List<ListDetails> groupListWithProductsById1(List<ListWithDetailsRow> listWithDetailsRows) {

        return listWithDetailsRows.stream()
                .collect(Collectors.groupingBy(ListWithDetailsRow::getListId))
                .values()
                .stream()
                .flatMap(Collection::stream)
                .map(sl -> new ListDetails(
                        sl.getName(),
                        sl.getListId(),
                        sl.getCustomerId(),
                        sl.getCreatedAt(),
                        sl.getUpdatedAt(),
                        newArrayList(
                                new ListProductDetails(
                                        sl.getProductId(),
                                        sl.getQuantity(),
                                        sl.getAddedAt()))))
                .collect(Collectors.toList());

但是通过这个实现,我收到了 ListDetails 列表 class

但目标是接收具有扁平化产品结构的列表,因为它们具有相同的 ID 组。 我知道我可以使用以下方法扁平化这个产品结构:

listDetails.stream().flatMap(sl -> sl.getProducts().stream()).collect(Collectors.toList())

但不知道groupingBy()操作后如何正确使用。将不胜感激您的建议。干杯!

如果我没理解错的话,你想做的是:

public List<ListDetails> groupListWithProductsById1(List<ListWithDetailsRow> listWithDetailsRows) {
    return listWithDetailsRows.stream()
        .collect(Collectors.groupingBy(ListWithDetailsRow::getListId)).values().stream()
        .map(rows ->
            new ListDetails(
                rows.get(0).getName(),
                rows.get(0).getListId(),
                rows.get(0).getCustomerId(),
                rows.get(0).getCreatedAt(),
                rows.get(0).getUpdatedAt(),
                rows.stream().map(row -> new ListProductDetails(
                    row.getProductId(), row.getQuantity(), row.getAddedAt()
                )).collect(Collectors.toList())
            )
    ).collect(Collectors.toList());
}

按列表 ID 分组后,您有一个 Collection<List<ListWithDetailsRow>> 作为返回地图的 values()。集合中的每个列表代表一个组。

然后你可以map每组一个ListDetailsnamelistIdcustomerIdcreatedAtupdatedAt 字段 ListDetails 可以取自组中的任意元素(我我选择了第一个),因为每个元素对于这些字段都应该具有相同的值。

对于 products 字段,只需 map ListWithDetailsRowListProductDetails 并收集到列表中。