Issue
Let's say that I have a list of dtos like:
@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;
}
I would like to map the above one to the:
@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;
}
where ListProductDetails looks like:
@RequiredArgsConstructor
@Builder
@Getter
@Setter
public class ListProductDetails {
private final String productId;
private final Integer quantity;
private final LocalDateTime addedAt;
}
So far I have:
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());
but with this implementation, I am receiving List of ListDetails class
but the goal is to receive List with a flattened structure of products because they have the same id group. I know that I can flat this product structure by using:
listDetails.stream().flatMap(sl -> sl.getProducts().stream()).collect(Collectors.toList())
but I don't know how to use it properly after the groupingBy()
operation. Will be grateful for suggestions. Cheers!
Solution
If I understand correctly, you want to do:
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());
}
After grouping by the list ID, you have a Collection<List<ListWithDetailsRow>>
as the values()
of the returned map. Each of the lists in the collection represents a group.
You can then map
each group to a ListDetails
. The name
, listId
, customerId
, createdAt
and updatedAt
fields of the ListDetails
can be taken from an arbitrary element in the group (I've chosen the first one), since every element should have the same values for those fields.
For the products
field, just map
the ListWithDetailsRow
s to ListProductDetails
and collect to a list.
Answered By - Sweeper
Answer Checked By - Willingham (JavaFixing Volunteer)