- Contents -
Collectors::groupingBy
JavaのListから、グループ化するためによく使うCollectors::groupingBy ですが、
グルーピングされた要素は、特定のキーごとにリスト化されます。
List<V>
から、特定のキーで
Map<K, List<V>>
こんな構造にする事ができます。
Map<K, List<V>>
サンプル
サンプルで、こんなa,bのメンバ変数をもつ単純なクラスがあるとして、
これのリストから、aの値でグルーピングしたMapを作成してみましょう。
class Sample {
int a;
int b;
public Sample(int a, int b) {
this.a = a;
this.b = b;
}
@Override
public String toString() {
return "Sample{" +
"a=" + a +
", b=" + b +
'}';
}
}
適当にリストを用意
List<Sample> list = Arrays.asList(
new Sample(1, 11),
new Sample(1, 12),
new Sample(2, 21),
new Sample(2, 22),
new Sample(2, 23),
new Sample(2, 24),
new Sample(3, 31),
new Sample(3, 32),
new Sample(3, 33));
グルーピング化してみます。
// aでグルーピングする
Map<Integer, List<Sample>> map1 = list.stream()
.collect(Collectors.groupingBy(o -> o.a));
// テキスト出力
for (Map.Entry<Integer, List<Sample>> entry : map1.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Collectors.groupingBy(o -> o.a)
で、グルーピングします。
出力結果は以下のように、aの値によって、グルーピングされた要素がリストになります。
Map<Integer, List<Sample>>
1: [Sample{a=1, b=11}, Sample{a=1, b=12}]
2: [Sample{a=2, b=21}, Sample{a=2, b=22}, Sample{a=2, b=23}, Sample{a=2, b=24}]
3: [Sample{a=3, b=31}, Sample{a=3, b=32}, Sample{a=3, b=33}]
多重Mapにしたい
このList<V>
の部分を、さらにMap化したいときは、
Collectors::groupingBy の第二引数にさらに、reductionを指定する事で実現できます。
Map<K1, Map<K2, V>>
こんな構造にしたいと思います。
K1がメンバ変数a、K2がメンバ変数bになるようにします。
Map<K1, Map<K2, V>>
サンプル
// aでグルーピングして、更にbでMap化
Map<Integer, Map<Integer, Sample>> map2 = list.stream()
.collect(Collectors.groupingBy(o -> o.a, Collectors.toMap(o -> o.b, o -> o)));
// テキスト出力
for (Map.Entry<Integer, Map<Integer, Sample>> entry : map2.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
Collectors.groupingBy(o -> o.a, Collectors.toMap(o -> o.b, o -> o))
groupingByの第二引数に、更に下流となるreductionを指定しています。
1: {11=Sample{a=1, b=11}, 12=Sample{a=1, b=12}}
2: {21=Sample{a=2, b=21}, 22=Sample{a=2, b=22}, 23=Sample{a=2, b=23}, 24=Sample{a=2, b=24}}
3: {32=Sample{a=3, b=32}, 33=Sample{a=3, b=33}, 31=Sample{a=3, b=31}}
出力結果は上記のように、
Map<Integer, Map<Integer, Sample>>
という形にすることができました。
ちなみに、a,b共に同一の要素が存在すると、下記のように例外が発生します。
まぁキーがバッティングした場合、よしなに上書きされるよりは例外が出てくれる方が良いでしょう。
Exception in thread "main" java.lang.IllegalStateException: Duplicate key Sample{a=2, b=24}
おしまい。
groupingByの第二引数は、downstream reduction となっていて、
Collectors.toSet()や、さらにgroupingByを指定することもできます。
for文でくるくる回して書いていたものが、結構スッキリ書けるようになるので、使ってみてはいかがでしょう。
1件のコメント