簡體   English   中英

優雅的方式到flatMapBy中的flatMap集

[英]Elegant way to flatMap Set of Sets inside groupingBy

所以我有一段代碼,我在迭代一個數據列表。 每一個都是一個ReportData ,它包含一個具有Long caseId和一個Ruling的案例。 每項Ruling都有一項或多項Payment 我希望將帶有caseIdMap作為鍵和付款組作為值(即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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM