[英]Elegant way to flatMap Set of Sets inside groupingBy
所以我有一段代碼,我在迭代一個數據列表。 每一個都是一個ReportData
,它包含一個具有Long caseId
和一個Ruling
的案例。 每項Ruling
都有一項或多項Payment
。 我希望將帶有caseId
的Map
作為鍵和付款組作為值(即Map<Long, Set<Payments>>
)。
案例在行之間並不是唯一的,但案例是。
換句話說,我可以有幾個具有相同大小寫的行,但它們將具有唯一的規則。
下面的代碼給我一個Map<Long, Set<Set<Payments>>>
這幾乎就是我想要的,但我一直在努力找到在給定上下文中flatMap最終集合的正確方法。 我一直在做着使用這個映射使邏輯正常工作的解決方法,但是我非常想修復算法以將這組付款正確地組合成一個集合,而不是創建一組集合。
雖然使用Java流進行flatMapping似乎是一個有點熱門的話題,但我一直在搜索並找不到相同類型的迭代問題。
rowData.stream()
.collect(Collectors.groupingBy(
r -> r.case.getCaseId(),
Collectors.mapping(
r -> r.getRuling(),
Collectors.mapping(ruling->
ruling.getPayments(),
Collectors.toSet()
)
)));
另一個JDK8解決方案:
Map<Long, Set<Payment>> resultSet =
rowData.stream()
.collect(Collectors.toMap(p -> p.Case.getCaseId(),
p -> new HashSet<>(p.getRuling().getPayments()),
(l, r) -> { l.addAll(r);return l;}));
或者從JDK9開始,您可以使用flatMapping
收集器:
rowData.stream()
.collect(Collectors.groupingBy(r -> r.Case.getCaseId(),
Collectors.flatMapping(e -> e.getRuling().getPayments().stream(),
Collectors.toSet())));
最干凈的解決方案是定義您自己的收集器:
Map<Long, Set<Payment>> result = rowData.stream()
.collect(Collectors.groupingBy(
ReportData::getCaseId,
Collector.of(HashSet::new,
(s, r) -> s.addAll(r.getRuling().getPayments()),
(s1, s2) -> { s1.addAll(s2); return s1; })
));
我首先想到的另外兩個解決方案但實際上效率和可讀性較低,但仍然避免構建中間Map
:
使用Collectors.reducing()
合並內部集合:
Map<Long, Set<Payment>> result = rowData.stream()
.collect(Collectors.groupingBy(
ReportData::getCaseId,
Collectors.reducing(Collections.emptySet(),
r -> r.getRuling().getPayments(),
(s1, s2) -> {
Set<Payment> r = new HashSet<>(s1);
r.addAll(s2);
return r;
})
));
reducing
操作將合並具有相同caseId
的條目的Set<Payment>
。 但是,如果您需要進行大量合並,則可能會導致很多副本的副本。
另一種解決方案是使用下游收集器來平鋪嵌套集合:
Map<Long, Set<Payment>> result = rowData.stream()
.collect(Collectors.groupingBy(
ReportData::getCaseId,
Collectors.collectingAndThen(
Collectors.mapping(r -> r.getRuling().getPayments(), Collectors.toList()),
s -> s.stream().flatMap(Set::stream).collect(Collectors.toSet())))
);
基本上它將所有匹配的caseId
集合放在一個List
,然后將列表的flatmaps放入一個Set
。
可能有更好的方法來做到這一點,但這是我發現的最好的方法:
Map<Long, Set<Payment>> result =
rowData.stream()
// First group by caseIds.
.collect(Collectors.groupingBy(r -> r.case.getCaseId()))
.entrySet().stream()
// By streaming over the entrySet, I map the values to the set of payments.
.collect(Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().stream()
.flatMap(r -> r.getRuling().getPayments().stream())
.collect(Collectors.toSet())));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.