Java 8 Lambdas flatmapping, groupingBy 和 mapping 得到 T 和 List 的 Map<K>

Java 8 Lambdas flatmapping, groupingBy and mapping to get a Map of T and List<K>

这是我目前的情况:

Map<Care, List<Correlative>> mapOf = quickSearchList
                .stream()
                .map(QuickSearch::getFacility)
                .collect(Collectors.flatMapping(facility -> facility.getFacilityCares().stream(),
                    Collectors.groupingBy(FacilityCare::getCare,
                        Collectors.mapping(c -> {
                            final Facility facility = new Facility();
                            facility.setId(c.getFacilityId());
                            return Correlative.createFromFacility(facility);
                        }, Collectors.toList()))));

我有一个快速搜索列表。快速搜索中的每个项目都有一个设施,如:

public class QuickSearch {
  Facility facility;
}

在每个设施中,都有一个 FacilityCare 列表,如:

public class Facility {
  List<FacilityCare> facilityCares;
}

最后,FacilityCare 有 Care 属性,如:

public class FacilityCare {
   Care care;
}

现在的想法是将 QuickSearch 的列表转换为 <Care, List<Correlative>> 的地图。 在上面的示例中,mapping() 函数中的代码是伪造的。 FacilityCare 只有 facilityID 而没有 Facility 实体。我希望在 flatMapping 中作为参数的设施对象在 mapping() 函数中再次成为我的参数,如:

Collectors.mapping(c -> Correlative.createFromFacility(facility)) 

其中“facility”与 flatMapping 中的对象相同。

有什么办法可以实现吗?如果需要进一步解释,请告诉我。

编辑: 这是一个没有充分利用收集器的解决方案。

final Map<Care, List<Correlative>> mapToHydrate = new HashMap<>();

 quickSearchList
  .stream()
  .map(QuickSearch::getFacility)
  .forEach(facility -> {
    facility.getFacilityCares()
      .stream()
      .map(FacilityCare::getCare)
      .distinct()
      .forEach(care -> {
        mapToHydrate.computeIfAbsent(care, care -> new ArrayList<>());
        mapToHydrate.computeIfPresent(care, (c, list) -> {
          list.add(Correlative.createFromFacility(facility));
          return list;
        });
      });
    });
      

这是我根据提供的信息想出的。 FacilityCare 存储在一个临时数组中,稍后在所需的映射中进行处理。

Map<Care, List<Correlative>> mapOf = quickSearchList.stream()
        .map(QuickSearch::getFacility)
        .flatMap(facility -> facility
                .getFacilityCares().stream()
        .map(facCare->new Object[]{facility, facCare.getCare()}))
        .collect(Collectors.groupingBy(obj->(Care)obj[1], Collectors
                .mapping(obj -> Correlative.createFromFacility(
                        (Facility)obj[0]),
                        Collectors.toList())));

我准备了一些简单的测试数据,假设我了解最终目标,这似乎可行。对于提供的每种类型的 care,它将提供该 care 的所有设施放入相关的 facilities 列表中。

有时候,流并不是最好的解决方案。这似乎是这种情况,因为您在管道中丢失了每个 facility 个实例。

相反,您可以按如下方式进行:

Map<Care, List<Correlative>> mapToHydrate = new LinkedHashMap<>();
quickSearchList.forEach(q -> {
    Facility facility = q.getFacility();
    facility.getFacilityCares().forEach(fCare -> 
        mapToHydrate.computeIfAbsent(fCare.getCare(), k -> new ArrayList<>())
                    .add(Correlative.createFromFacility(facility)));
});

这使用 Map.computeIfAbsent 的 return 值(它是新创建的相关列表或已经存在的列表)。

从你的问题中不清楚为什么在将它们添加到地图之前需要不同的关注。


编辑: 从 Java 16 开始,您可能需要使用 Stream.mapMulti:

Map<Care, List<Correlative>> mapToHydrate = quickSearchList.stream()
    .map(QuickSearch::getFacility)
    .mapMulti((facility, consumer) -> facility.getFacilityCares()
        .forEach(fCare -> consumer.accept(Map.entry(fCare.getCare(), facility))))
    .collect(Collectors.groupingBy(
        e -> e.getKey(), 
        Collectors.mapping(
            e -> Correlative.createFromFacility(e.getValue()),
            Collectors.toList())));

受@fps 回答的启发,我想出了一个暂时可行的解决方案(pre-Java16)。

Map<Care, List<Correlative>> mapOf = quickSearchList
            .stream()
            .map(QuickSearch::getFacility)
            .map(expandIterable())
            .collect(
                Collectors.flatMapping(map -> map.entrySet().stream(),
                    Collectors.groupingBy(Map.Entry::getKey,
                        Collectors.mapping(entry -> Correlative.createFromFacility(entry.getValue()),
                            Collectors.toList()
                        )
                    )
                ));
    }

    public Function<Facility, Map<Care, Facility>> expandIterable() {
        return facility -> facility.getFacilityCares()
            .stream()
            .map(FacilityCare::getCare)
            .distinct()
            .collect(Collectors.toMap(c -> c, c -> facility));
    }

基本上,我添加了一个方法调用,该方法调用 returns 一个以 Facility 作为参数的函数和 returns 一个 Map of Care 作为键,以 Facility 作为值。该图用于上一个流的集合。