Java 逆引き集 | partitioningBy(true/false に分割) — 二分集計

Java Java
スポンサーリンク

partitioningBy(true/false に分割) — 二分集計

Stream API の Collectors.partitioningBy は「条件に合うかどうか」で true/false の二分割を行う便利な集約方法です。
SQL の「WHERE 条件で2グループに分ける」イメージで、合格/不合格、偶数/奇数などの二分集計に向いています。


基本の仕組み

  • partitioningBy(predicate):
    • 条件を満たす要素は true グループ、満たさない要素は false グループに分類。
    • 戻り値は Map<Boolean, List<T>>
  • partitioningBy(predicate, downstreamCollector):
    • true/false ごとにさらに集約(件数、合計、平均など)。
    • 戻り値は Map<Boolean, R>

基本コード例

条件で二分割(偶数/奇数)

import java.util.*;
import java.util.stream.*;

public class PartitionBasic {
    public static void main(String[] args) {
        List<Integer> nums = List.of(1,2,3,4,5,6);

        Map<Boolean, List<Integer>> partition =
            nums.stream()
                .collect(Collectors.partitioningBy(n -> n % 2 == 0));

        System.out.println(partition);
        // {false=[1, 3, 5], true=[2, 4, 6]}
    }
}
Java

件数を数える(downstream に counting)

List<Integer> nums = List.of(1,2,3,4,5,6);

Map<Boolean, Long> counts =
    nums.stream()
        .collect(Collectors.partitioningBy(n -> n % 2 == 0,
                                           Collectors.counting()));

System.out.println(counts);
// {false=3, true=3}
Java

合計値を出す(summingInt)

record Student(String name, int score) {}

List<Student> students = List.of(
    new Student("Tanaka",80),
    new Student("Sato",55),
    new Student("Ito",90)
);

Map<Boolean, Integer> sumScores =
    students.stream()
            .collect(Collectors.partitioningBy(s -> s.score >= 60,
                                               Collectors.summingInt(Student::score)));

System.out.println(sumScores);
// {false=55, true=170}
Java

例題で理解する

例題1: 学生を「合格/不合格」に分ける

Map<Boolean, List<Student>> grouped =
    students.stream()
            .collect(Collectors.partitioningBy(s -> s.score >= 60));

System.out.println(grouped);
// {true=[Tanaka, Ito], false=[Sato]}
Java
  • ポイント: true が「合格」、false が「不合格」。

例題2: 商品を「高額/低額」に分けて件数集計

record Product(String name, int price) {}

List<Product> products = List.of(
    new Product("A",100),
    new Product("B",250),
    new Product("C",160)
);

Map<Boolean, Long> counts =
    products.stream()
            .collect(Collectors.partitioningBy(p -> p.price >= 200,
                                               Collectors.counting()));

System.out.println(counts);
// {false=2, true=1}
Java

例題3: ログを「ERROR 含む/含まない」で分類

List<String> logs = List.of("INFO start","ERROR failed","WARN retry","ERROR timeout");

Map<Boolean, List<String>> partition =
    logs.stream()
        .collect(Collectors.partitioningBy(l -> l.contains("ERROR")));

System.out.println(partition);
// {false=[INFO start, WARN retry], true=[ERROR failed, ERROR timeout]}
Java

テンプレート集

  • 基本二分割
Map<Boolean, List<T>> map =
    stream.collect(Collectors.partitioningBy(x -> 条件));
Java
  • 件数集計
Map<Boolean, Long> map =
    stream.collect(Collectors.partitioningBy(x -> 条件, Collectors.counting()));
Java
  • 合計集計
Map<Boolean, Integer> map =
    stream.collect(Collectors.partitioningBy(x -> 条件, Collectors.summingInt(x -> 値)));
Java
  • 平均集計
Map<Boolean, Double> map =
    stream.collect(Collectors.partitioningBy(x -> 条件, Collectors.averagingInt(x -> 値)));
Java

落とし穴と回避策

  • キーは必ず true/false: groupingBy と違ってキーは Boolean 固定。2分割しかできない。
  • 大量データ: true/false 両方のリストを保持するため、メモリ負荷に注意。件数や合計だけ欲しいなら downstream Collector を使う。
  • 条件の意味を明確に: true/false の意味が分かりにくい場合は、ラップして Enum や groupingBy を使う方が読みやすい。

まとめ

  • partitioningBy は「条件に合うかどうか」で true/false に二分割する。
  • downstream Collector を組み合わせると件数・合計・平均などの二分集計が簡単。
  • 合格/不合格、偶数/奇数、エラー/正常など、二値分類に最適。

👉 練習課題: 「社員リストを年齢30以上かどうかで partitioningBy し、各グループの人数を数える」コードを書いてみると、二分集計の便利さが体感できます。

タイトルとURLをコピーしました