Java / Ope / Collection操作 / Stream / 終端処理 / collect / groupingBy

Java / Ope / Collection操作 / Stream / 終端処理 / collect / groupingBy

コレクションに対して SQL の GROUP BY のような操作ができる。

List<String> sList = new ArrayList<>();
sList.add("1hoge");
sList.add("1piyo");
sList.add("2fuga");
sList.add("2hogehoge");
sList.add("3piyopiyo");
sList.add("3fugafuga");
 
Map<String, List<String>> result = sList.stream().collect(Collectors.groupingBy(s -> s.substring(0, 1)));
System.out.println(result); //=> {1=[1hoge, 1piyo], 2=[2fuga, 2hogehoge], 3=[3piyopiyo, 3fugafuga]}

groupingBy メソッドに対して評価軸を決定する処理を渡すとそれをキーにしたマップに対して各要素グルーピングしたリストで返却してくれる。

ORM の OneToMany をまとめるような場合に非常に有効に効く。

複合キーでグルーピングしたければ、そのキーを表すクラスを作ってそこで equals をオーバーライドするか、簡単に済ませたいなら一意になるように String を生成してもよいだろう。

この方法では、Map< T, List<E> > になってしまうつまり key は グルーピング基準に使ったキーの型で、Value は元の要素の List となる。

これを変えたい場合はこうする。groupingBy の第2引数にさらに終端処理を記述すればよい。

Set<String> sSet = new HashSet<>();
sSet.add("1hoge");
sSet.add("1piyo");
sSet.add("2fuga");
sSet.add("2hogehoge");
sSet.add("3piyopiyo");
sSet.add("3fugafuga");
 
Map<String, Set<String>> result = sSet.stream().collect(
        Collectors.groupingBy(
                s -> s.substring(0, 1),
                Collectors.toSet()));
System.out.println(result); //=> {1=[1hoge, 1piyo], 2=[2fuga, 2hogehoge], 3=[3piyopiyo, 3fugafuga]}

これをグルーピングした各要素を独自クラスに集約したい場合は Collector::of してやればよい

Map<String, Hoge> result = sSet.stream().collect(
        Collectors.groupingBy(
                s -> s.substring(0, 1),
                Collectors.of(
                        () -> new Hoge(),
                        (Hoge s, String v) -> {
                            s.addMe(v);
                        },
                        (Hoge s1, Hoge s2) -> {
                            s1.addMe(s2);
                            return s1
                        },
                        Characteristics.IDENTITY_FINISH
                )
        )
);
java/ope/collection_ope/stream/tarminator/collect/groupingby.txt · 最終更新: 2020-12-31 16:23 by ore