Java 逆引き集 | Collections.shuffle / sort / reverse — リスト操作ユーティリティ

Java Java
スポンサーリンク

Collections.shuffle / sort / reverse — リスト操作ユーティリティ

リストの「並び替え」「逆順」「ランダム化」を一発でやれるのが Collections ユーティリティ。初心者でも迷わない使いどころ、コード例、落とし穴をまとめます。


基本の3メソッド

  • shuffle: リスト要素の順序をランダムに並べ替える(均等なシャッフル)。
  • sort: リストを昇順(自然順序)や任意の比較ルールで並べ替える。
  • reverse: 現在の並びをそのまま逆順にする(単純反転)。

すぐ試せる基本例

import java.util.*;

public class ListOpsBasics {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(Arrays.asList(5, 3, 8, 1));

        // 1) sort: 昇順(自然順序)
        Collections.sort(nums);                 // [1, 3, 5, 8]
        // 同等: nums.sort(Comparator.naturalOrder());

        // 2) reverse: 逆順に反転
        Collections.reverse(nums);              // [8, 5, 3, 1]

        // 3) shuffle: ランダムに並び替え
        Collections.shuffle(nums);              // 実行ごとに異なる順序

        // 再現可能なシャッフル(シード指定)
        Collections.shuffle(nums, new Random(42));
    }
}
Java

sort の使い分け(Comparator で柔軟な並べ替え)

文字列を長さ順、同じ長さは辞書順

List<String> words = new ArrayList<>(List.of("cat", "apple", "hi", "banana"));
words.sort(Comparator
    .comparingInt(String::length)
    .thenComparing(Comparator.naturalOrder()));
// 結果: [hi, cat, apple, banana]
Java

降順(大きい順)

List<Integer> nums = new ArrayList<>(List.of(5, 3, 8, 1));
nums.sort(Comparator.reverseOrder()); // [8, 5, 3, 1]
Java

フィールドで並べ替え(オブジェクトリスト)

class User {
    final String name;
    final int age;
    User(String name, int age) { this.name = name; this.age = age; }
    public String toString() { return name + "(" + age + ")"; }
}

List<User> users = new ArrayList<>(List.of(
    new User("Tanaka", 30), new User("Sato", 22), new User("Kato", 22)));

users.sort(Comparator
    .comparingInt(u -> u.age)
    .thenComparing(u -> u.name));
// 結果: [Kato(22), Sato(22), Tanaka(30)]
Java
  • ポイント: comparing / thenComparing で「主キー→副キー」の順にルール記述。
  • 安定ソート: Java の sort は安定(同順位の元順序を保つ)。

shuffle の実践ポイント(再現性と配列対処)

  • 均等シャッフル: Collections.shuffle はリストに対して均等なランダム並び替え。
  • 再現可能: Random にシードを渡すと結果が固定され、テストしやすい。
List<String> cards = new ArrayList<>(List.of("A", "B", "C", "D"));
Collections.shuffle(cards, new Random(123)); // 毎回同じ並び
Java
  • 配列は直接不可: shuffle は List 用。配列なら一旦リスト化してから。
Integer[] arr = {1, 2, 3, 4, 5};
List<Integer> list = Arrays.asList(arr); // 固定長ビュー(要素は書き換え可)
Collections.shuffle(list);               // 配列中身がシャッフルされる
Java
  • 要素追加・削除もしたいなら、まず ArrayList にコピー
List<Integer> list2 = new ArrayList<>(Arrays.asList(arr));
Collections.shuffle(list2); // こちらは add/remove も可能
Java

reverse の使いどころ(単純反転)

List<String> logs = new ArrayList<>(List.of("e1", "e2", "e3"));
Collections.reverse(logs); // [e3, e2, e1]
Java
  • ソート後の反転: 「降順にしたい」が比較が面倒なら、昇順ソート → reverse でもOK。
  • 部分反転は自前: サブリスト取得して reverse 適用
List<Integer> nums = new ArrayList<>(List.of(1,2,3,4,5,6));
Collections.reverse(nums.subList(2, 5)); // 3..5の範囲を反転 → [1,2,5,4,3,6]
Java

例題で身につける

例題1: トランプの山札を作ってシャッフル

List<String> deck = new ArrayList<>();
for (String suit : List.of("♠", "♥", "♦", "♣")) {
    for (int rank = 1; rank <= 13; rank++) {
        deck.add(suit + rank);
    }
}
Collections.shuffle(deck);
System.out.println(deck.subList(0, 5)); // 先頭5枚(毎回ランダム)
Java

例題2: 顧客一覧を「購入額降順、同額は名前昇順」

class Customer { final String name; final int total; Customer(String n, int t){name=n; total=t;} }
List<Customer> cs = new ArrayList<>(List.of(
    new Customer("Tanaka", 12000), new Customer("Sato", 12000), new Customer("Kato", 9000)));

cs.sort(Comparator
    .comparingInt((Customer c) -> c.total).reversed()
    .thenComparing(c -> c.name));
// 結果: Tanaka(12000), Sato(12000), Kato(9000)
Java

例題3: 最新ログを先頭にした表示(逆順)

List<String> logs = new ArrayList<>(List.of("10:00", "10:05", "10:10"));
Collections.reverse(logs);
for (String l : logs) System.out.println(l); // 10:10 → 10:05 → 10:00
Java

性能・仕様の要点

  • sort: 平均計算量はだいたい O(n log n)。Java の実装は安定ソート。
  • shuffle: O(n)。均等なランダム化(Fisher–Yates系)。
  • reverse: O(n)。リンク構造でなければ原地反転(リストの種類に依存)。
  • 破壊的操作: 3メソッドともリストを「その場で」書き換える。元の順序が必要ならコピーを作る。
List<Integer> sortedCopy = new ArrayList<>(nums);
Collections.sort(sortedCopy);
Java

よくある落とし穴と回避策

  • Arrays.asList の落とし穴: 固定長ビュー。add/remove で例外。→ 変更したいなら new ArrayList<>(…) にコピー。
  • ロケール依存の文字列比較: 日本語やアクセントを正しく並べたいなら Collator を使う。
import java.text.Collator;
Collator ja = Collator.getInstance(java.util.Locale.JAPAN);
words.sort(ja::compare);
Java
  • Comparator の null: null を含むなら nullsFirst/nullsLast を明示。
list.sort(Comparator.nullsLast(Comparator.naturalOrder()));
Java
  • シャッフルの再現性: テストで固定したい → Random(シード) を渡す。
  • 不変リストへの適用: List.of(…) は不変。sort/reverse/shuffle は例外。→ まず可変リストへコピー。

テンプレート集

昇順・降順

list.sort(Comparator.naturalOrder());   // 昇順
list.sort(Comparator.reverseOrder());   // 降順
Java

複合キー

list.sort(Comparator.comparing(Type::key1)
                    .thenComparing(Type::key2));
Java

カスタム比較(数値の絶対値で昇順)

list.sort(Comparator.comparingInt(Math::abs));
Java

部分範囲の操作

Collections.sort(list.subList(from, to));    // 部分ソート(昇順)
Collections.reverse(list.subList(from, to)); // 部分反転
Java

シャッフル(シード指定)

Collections.shuffle(list, new Random(12345));
Java

まとめ

  • 並べ替えは sort、ランダム化は shuffle、逆順は reverse。まずこの3つを使い分ければ困らない。
  • Comparator を使えば「業務の並びルール」をそのままコード化できる。複合キー、降順、null対応、言語別比較を覚えておくと強い。
  • 3メソッドは破壊的操作。元の順序が必要ならコピーしてから適用するのが安全。
タイトルとURLをコピーしました