web-dev-qa-db-ja.com

Java Streams GroupingByおよびカウントによるフィルタリング(SQLのHAVINGと同様)

Java(9+)ストリームは、SQLと同様のHAVING句をサポートしていますか?使用例:グループ化してから特定の数のすべてのグループを削除します。次のSQLを書くことは可能ですか? Java stream?

GROUP BY id
HAVING COUNT(*) > 5

私が思いつくことができる最も近いものは:

input.stream()
        .collect(groupingBy(x -> x.id()))
        .entrySet()
        .stream()
        .filter(entry -> entry.getValue().size() > 5)
        .collect(toMap(Map.Entry::getKey, Map.Entry::getValue));

ただし、グループ化された結果のentrySetを2回収集して抽出することは奇妙に感じられ、特にターミナルcollectの呼び出しは基本的にマップをそれ自体にマッピングしています。

collectingAndThenおよびfilteringコレクターがあることがわかりますが、それらが私の問題を解決するかどうか(またはそれらを正しく適用する方法)がわかりません。

上記のより良い(より慣用的な)バージョンはありますか、それとも中間マップに収集し、それをフィルタリングしてから最終マップに収集するのに行き詰まっていますか?

7
knittl

私が知っている唯一の方法は Collectors.collectingAndThenfinisher関数内で同じ実装を使用:

Map<Integer, List<Item>> a = input.stream().collect(Collectors.collectingAndThen(
        Collectors.groupingBy(Item::id),
        map -> map.entrySet().stream()
                             .filter(e -> e.getValue().size() > 5)
                             .collect(Collectors.toMap(Entry::getKey, Entry::getValue))));
2
Nikolas

より読みやすいコードが必要な場合は、(再ストリームの代替として)Guava filterValues関数を使用することもできます。

これはマップの変換を可能にし、Javaストリームよりも短くて読みやすい構文を提供することがあります。

Map<A,B> unfiltered = Java stream groupingby
return Maps.filterValues(unfiltered, value -> value.size() > 5);
0
CodeScale