menu
書いてる野郎
orebike@gmail.com
コレクションに対して 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 ) ) );