繁体   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