Collections.frequency / disjoint などユーティリティ — コレクション比較
配列やリスト、セット同士を「重複数の比較」「共通要素の有無」「部分一致」などで比べたいとき、java.util.Collections のユーティリティが役に立ちます。初心者向けに、頻出メソッドの使い方と例題をまとめます。
基本ユーティリティの概要
- frequency: コレクション内で、ある要素が何回出現するかを数える。
- disjoint: 2つのコレクションが共通要素をまったく持たないか(交わらないか)を判定する。
- indexOfSubList / lastIndexOfSubList: リストの中から「部分リスト」が現れる最初/最後の位置を探す。
- max / min: 要素の最大/最小を取得(自然順序または Comparator)。
- addAll / replaceAll / swap / reverse / sort: 比較に併用されることの多い、整形・準備用の操作。
すぐ試せる基本例
import java.util.*;
public class CollectionsCompareBasics {
public static void main(String[] args) {
List<String> a = List.of("apple", "banana", "apple", "cherry");
List<String> b = List.of("grape", "banana", "melon");
// frequency: 要素の出現回数
System.out.println(Collections.frequency(a, "apple")); // 2
System.out.println(Collections.frequency(a, "banana")); // 1
System.out.println(Collections.frequency(a, "orange")); // 0
// disjoint: 共通要素があるか
System.out.println(Collections.disjoint(a, b)); // false("banana"が共通)
// indexOfSubList: 部分リストの位置
List<String> sub = List.of("banana", "apple");
System.out.println(Collections.indexOfSubList(a, sub)); // 1(a[1..2]が一致)
System.out.println(Collections.lastIndexOfSubList(a, sub)); // 1(最後も1)
}
}
Javaよく使う比較タスクと実装パターン
- 共通要素の有無(重なりチェック)
- 使いどころ: フィルタ処理前の早期判定、タグ同士の排他性チェック。
boolean noOverlap = Collections.disjoint(list1, list2); // 重なりなしなら true
Java- 出現回数の集計(多重比較の下準備)
- 使いどころ: ログの単語頻度、アンケート回答の集計など。
int count = Collections.frequency(items, target);
Java- 部分一致(サブリスト探索)
- 使いどころ: シーケンスのパターン検出、連続データの一致確認。
int pos = Collections.indexOfSubList(big, small);
int last = Collections.lastIndexOfSubList(big, small);
Java- 最大/最小(ソート不要で一発取得)
String mx = Collections.max(words); // 自然順
String mn = Collections.min(words, Comparator.comparingInt(String::length)); // 長さ最小
Java例題で理解する
例題1: タグの衝突チェック(disjoint)
List<String> required = List.of("A", "B");
List<String> forbidden = List.of("B", "C");
boolean ok = Collections.disjoint(required, forbidden); // false("B"が共通→衝突)
System.out.println(ok ? "OK" : "NG: conflict");
Java- ねらい: 共通要素の存在を一発で判定して、矛盾の早期検出。
例題2: 文章中の重要語の頻度(frequency)
List<String> tokens = List.of("java", "api", "java", "class", "java");
int freqJava = Collections.frequency(tokens, "java"); // 3
System.out.println("java: " + freqJava);
Java- ねらい: 単純集計を短く書く。
例題3: 連続パターンの検出(indexOfSubList)
List<Integer> series = List.of(1,2,3,2,3,4,2,3);
List<Integer> pat = List.of(2,3);
System.out.println(Collections.indexOfSubList(series, pat)); // 1
System.out.println(Collections.lastIndexOfSubList(series, pat)); // 6
Java- ねらい: リスト内での連続出現範囲を素早く調べる。
実務でのコツと落とし穴
- 比較の前処理を整える:
- 重複を無視したい: 片方を
new HashSet<>(list)にしてからdisjointを使うと高速化。 - 大小文字やトリム: 文字列比較は前処理(小文字化・トリム)で意図どおりに。
- 重複を無視したい: 片方を
- equals が比較ルールになる:
- 前提:
frequencyやdisjointはequalsで同値判定。 - 対策: 独自オブジェクトは
equals/hashCodeを正しく実装。
- 前提:
- 部分一致は連続のみ:
- 注意:
indexOfSubListは「連続部分」の一致のみ。飛び飛び一致は対象外。 - 対策: 飛び飛び一致は自前ロジックやストリームで構築。
- 注意:
- 性能・サイズ感:
- frequency: リストが大きいと線形走査コスト。複数値を同時に数えるなら、マップで一度に集計したほうが速い。
- disjoint: 片方がセットだと平均高速。大規模ならどちらかをセット化する。
ミニテンプレート集
- 共通要素の有無(高速化版)
boolean noOverlap = Collections.disjoint(new HashSet<>(list1), list2);
Java- 複数値の頻度を一括集計(Map版)
Map<String, Integer> freq = new HashMap<>();
for (String w : words) freq.merge(w, 1, Integer::sum);
Java- 部分リストの検出と切り出し
int start = Collections.indexOfSubList(big, sub);
if (start >= 0) {
List<Type> slice = big.subList(start, start + sub.size());
}
Java- 最小/最大(Comparator付き)
Type min = Collections.min(list, Comparator.comparing(Type::key));
Type max = Collections.max(list, Comparator.comparing(Type::key));
Javaまとめ
- frequency は出現回数、disjoint は共通要素の有無、indexOfSubList は連続部分一致の位置検出に使う。
- 比較の前処理(大小文字・トリム・セット化)や
equalsルールの理解が精度と性能を左右する。 - 大規模・複雑な比較は「一括集計(Map)」「セット化」「Comparator の活用」で効率よく解くのがコツ。
