我有一個帶有嵌套串列欄位的 DTO 物件串列。目的是按欄位對它們進行分組并合并,使用 Streams API 對串列進行排序。
class DTO {
private Long id;
private List<ItemDTO> items;
}
class ItemDTO {
private Long priority;
private Long value;
}
// input
List<DTO> dtoList = List.of(
DTO(1, List.of(ItemDTO(1, 1), ItemDTO(7, 2))),
DTO(2, List.of(ItemDTO(1, 1), ItemDTO(2, 2))),
DTO(1, List.of(ItemDTO(10, 3), ItemDTO(1, 4)))
);
需要用 id 欄位對這些嵌套物件進行分組,并按欄位優先級降序合并所有專案。這個 dtoList 的最終結果將是這樣的:
// output
List<DTO> resultList = [
DTO(1, List.of(ItemDTO(10,3), ItemDTO(7,2), ItemDTO(1,1), ItemDTO(1,4)),
DTO(2, List.of(ItemDTO(2,2), ItemDTO(1,1),
];
我們可以使用 Streams API 實作這一點嗎?提前致謝。
uj5u.com熱心網友回復:
您可以通過將資料分組來創建中間映射,id然后將每個條目轉換為新DTO物件。
為此,您可以使用內置收集器的組合groupingBy()并flatMapping()創建中間映射。
為了對每個映射的專案進行排序id,flatMapping()正在與collectionAndThen().
正如@shmosel所指出的,flatMapping()它是Java 9 的優點之一。您可能還認為它是一種提醒,也許是時候轉向提供的模塊化系統和其他有用的特性了(Java 8 的解決方案在下面提供) .
public static void main(String[] args) {
// input
List<DTO> dtoList = List.of(
new DTO(1L, List.of(new ItemDTO(1L, 1L), new ItemDTO(7L, 2L))),
new DTO(2L, List.of(new ItemDTO(1L, 1L), new ItemDTO(2L, 2L))),
new DTO(1L, List.of(new ItemDTO(10L, 3L), new ItemDTO(1L, 4L)))
);
List<DTO> result = dtoList.stream()
.collect(Collectors.groupingBy(DTO::getId,
Collectors.collectingAndThen(
Collectors.flatMapping(dto -> dto.getItems().stream(), Collectors.toList()),
(List<ItemDTO> items) -> {
items.sort(Comparator.comparing(ItemDTO::getPriority).reversed());
return items;
})))
.entrySet().stream()
.map(entry -> new DTO(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
result.forEach(System.out::println);
}
輸出
DTO{id = 1, items = [ItemDTO{10, 3}, ItemDTO{7, 2}, ItemDTO{1, 1}, ItemDTO{1, 4}]}
DTO{id = 2, items = [ItemDTO{2, 2}, ItemDTO{1, 1}]}
完全兼容Java 8的版本將如下所示:
List<DTO> result = dtoList.stream()
.collect(Collectors.groupingBy(DTO::getId,
Collectors.collectingAndThen(
Collectors.mapping(DTO::getItems, Collectors.toList()),
(List<List<ItemDTO>> items) ->
items.stream().flatMap(List::stream)
.sorted(Comparator.comparing(ItemDTO::getPriority).reversed())
.collect(Collectors.toList())
)))
.entrySet().stream()
.map(entry -> new DTO(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
uj5u.com熱心網友回復:
我將從一個簡單的分組開始,以獲取一個映射Map<Long,List<DTO>>并流過該映射的條目,并將每個條目映射到一個新的 DTO。您可以提取一個方法/函式來對ItemDTOs 進行排序:
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
....
Function<List<DTO>, List<ItemDTO>> func =
list -> list.stream()
.map(DTO::getItems)
.flatMap(List::stream)
.sorted(Comparator.comparing(ItemDTO::getPriority,Comparator.reverseOrder()))
.collect(Collectors.toList());
List<DTO> result =
dtoList.stream()
.collect(Collectors.groupingBy(DTO::getId))
.entrySet().stream()
.map(entry -> new DTO(entry.getKey(), func.apply(entry.getValue())))
//.sorted(Comparator.comparingLong(DTO::getId)) if the resulting list need to be sorted by id
.collect(Collectors.toList());
uj5u.com熱心網友回復:
Imo,這是最簡單的方法。我假設您已經為您的課程定義了適當的吸氣劑。
- 簡單地轉換為以 id 為鍵的地圖。
- 合并適當的串列
- 并回傳值并轉換為 ArrayList。
List<DTO> results = new ArrayList<>(dtoList.stream().collect(
Collectors.toMap(DTO::getId, dto -> dto, (a, b) -> {
a.getItems().addAll(b.getItems());
return a;
})).values());
然后根據您的要求簡單地對它們進行分類。在流構造中執行此操作不需要更多時間,但在我看來不那么混亂。
for (DTO d: results) {
d.getItems().sort(Comparator.comparing(ItemDTO::getPriority)
.reversed());
}
results.forEach(System.out::println);
列印(使用簡單toString的兩個類)
DTO[1, [ItemDTO[10, 3], ItemDTO[7, 2], ItemDTO[1, 1], ItemDTO[1, 4]]]
DTO[2, [ItemDTO[2, 2], ItemDTO[1, 1]]]
注意:List.of是不可變的,因此您無法更改它們。我會new ArrayList<>(List.of(...))在你的串列結構中使用。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/476755.html
