我在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();
答案 0 :(得分:2)
根据您的描述,您似乎想要过滤作为分组结果的地图。因此,您可以对分组结果应用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);
答案 1 :(得分:1)
正如您已经注意到的那样,遗憾的是,JDK的GROUP BY
API中没有流媒体Stream
操作(即使有流媒体distinct()
操作)。 collect()
是一个终端操作,它将组和聚合收集到具体的Map
。
但是,正如本article showing SQL clauses and their equivalents in Java 8 Streams中所述,您可以重新传输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))
));
答案 2 :(得分:1)
resultMap.values().removeIf(lst -> lst.size() < 3)
从结果中删除不需要的所有内容