Java 8 Streams API HAS 子句等效于 GroupingBy



>我在Streams API遇到了一个难以解决的问题。嗯,它是可以解决的,但从我能说的,在一次通话中并不优雅。下面,以FeatureContentWeight对象的流为例,我想按功能和内容进行分组,并获得每个功能和内容的最大权重。我在最后从Map中获取值,因为我不需要维护Map.问题是,我只想要包含 3 个以上项目的组。所以我想要每个功能和内容的最大权重,功能,内容对已超过给定计数。在SQL,这只是一个简单的HAVING条款。Streams API它看起来并不微不足道,但我只在Streams API呆了几天。

任何想法都值得赞赏。以下是我的方法,

List<FeatureContentWeight> nearestNeighbors = neighborPostings
    .stream()
    .collect(
    groupingBy(
        p -> FeatureContent.Create(p.getFeatureId(), p.getContentId()), 
        collectingAndThen(maxBy(comparingDouble(FeatureContentWeight::getWeight)),Optional::get))).values();

正如您所注意到的,不幸的是,JDK 的 Stream API 中没有流式处理GROUP BY操作(即使存在流式处理distinct()操作(。 collect() 是一种终端操作,它将组和聚合收集到一个具体的Map中。

但是,如本文所述,在 Java 8 Streams 中展示 SQL 子句及其等效项,您可以重新流式传输Map.entrySet()并对其执行进一步的操作。

应用于您的代码(我在这里做一些假设(:

Map<FeatureContentWeight, Double> nearestNeighbors = neighborPostings
    .stream()
    // GROUP BY featureId, contentId
    .collect(
        groupingBy(
            p -> FeatureContent.Create(p.getFeatureId(), p.getContentId())
        )
    )
    // HAVING count(*) >= 3
    .entrySet()
    .stream()
    .filter(e -> e.getValue().size() >= 3)
    // SELECT grp, MAX(weight)
    .map(e -> e.getValue().stream().collect(
        maxBy(comparingDouble(w -> w.getWeight))
    ));

从您的描述来看,您似乎要过滤作为分组结果的地图。因此,您可以对分组结果应用toMap收集器,然后过滤其values(),以便仅保留长度为 3 或更大的收集器。您可能也可以跳过地图创建并使用partitioningBy收集器,但这可能会更尴尬。

最后,对于转换地图,我发现 Guava 的辅助函数(如 Maps.filterValues()(有时提供比 Java 8 更短、更易读的语法(流语法对于列表来说很好,但对于地图来说有时会变得很糟糕(。如果你使用的是Java 8,你可以在Guava中使用闭包,所以你可以写一些类似的东西:

Map<A,B> unfiltered = <Java 8 grouping>
return Maps.filterValues(unfiltered, list -> list.size() > 3);
resultMap.values().removeIf(lst -> lst.size() < 3)

只需从结果中删除您不需要的所有内容

相关内容

  • 没有找到相关文章

最新更新