Arrays クラスユーティリティ(sort / binarySearch) — 配列操作
配列の並べ替えと検索は「まずソートしてから二分探索」が基本。Java の java.util.Arrays は、配列向けに高速な sort と正確な binarySearch を用意しています。初心者でも迷わない使い方、落とし穴、テンプレートをまとめます。
配列の前提と基本
- 固定長のデータ構造: 配列は作成後に長さを変えられません(要素の追加・削除は不可)。サイズやインデックスの扱いを理解した上で、内容の並び替え・検索を行います。
- 配列の型ごとのメソッド:
Arrays.sortはプリミティブ配列(int[]など)と参照型配列(String[]など)でオーバーロードされており、どちらも簡単に使えます。
Arrays.sort(並べ替え)
基本の昇順ソート
import java.util.Arrays;
public class SortBasics {
public static void main(String[] args) {
int[] numbers = {5, 3, 8, 1};
Arrays.sort(numbers); // 昇順に並べ替え
System.out.println(Arrays.toString(numbers)); // [1, 3, 5, 8]
}
}
Java- ポイント: 昇順の「自然順序」で並べ替え。文字列なら辞書順、数値なら小さい順になります。
降順ソート(参照型のみ)
String[] words = {"cat", "apple", "hi", "banana"};
Arrays.sort(words, java.util.Comparator.reverseOrder());
System.out.println(Arrays.toString(words)); // [hi, cat, banana, apple]
Java- 注意: 降順は
Comparatorを渡せる参照型配列で可能。プリミティブ配列は一度ラップ(Integer[]など)するか、昇順ソート後に自前で反転します。
カスタム比較(オブジェクト配列)
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 + ")"; }
}
User[] users = {
new User("Tanaka", 30), new User("Sato", 22), new User("Kato", 22)
};
// 年齢昇順、同年齢は名前昇順
java.util.Arrays.sort(users,
java.util.Comparator.comparingInt((User u) -> u.age)
.thenComparing(u -> u.name));
System.out.println(java.util.Arrays.toString(users));
// [Kato(22), Sato(22), Tanaka(30)]
Java- コツ:
comparingとthenComparingを使うと「主キー→副キー」の並びルールを読みやすく書けます。
Arrays.binarySearch(二分探索)
基本の使い方(見つかったらインデックス、なければ負の値)
import java.util.Arrays;
int[] sorted = {1, 3, 5, 7, 9, 11};
int idx1 = Arrays.binarySearch(sorted, 7); // 3(見つかった位置)
int idx2 = Arrays.binarySearch(sorted, 8); // 負の値(挿入位置規則)
System.out.println(idx1); // 3
System.out.println(idx2); // -5 など(実行環境で同じ)
Java- 前提: 配列は事前にソート済みである必要があります。未ソートのまま
binarySearchを使うと、結果が意図通りになりません。 - 返り値の規則: 要素が見つかった場合はそのインデックス。見つからない場合は「挿入すべき位置」を
-(insertionPoint) - 1の形で返します(負の値)。この規則により、戻り値から「どこに挿入すればよいか」を復元できます。 - 性能: 二分探索は配列長を毎回半分に絞るため、計算量はおおむね O(log n)。大規模データでも高速です。
使いこなしテンプレート(挿入位置を求める)
int pos = Arrays.binarySearch(sorted, target);
int insertionPoint = (pos >= 0) ? pos : -pos - 1; // ここに挿入すると順序が保てる
Java- 応用: ソート済み配列を保ったまま挿入位置を計算できます(ただし配列は固定長なので、挿入自体は別の構造が必要)。
文字列配列でも同様
String[] names = {"Alice", "Bob", "Carol", "Dave"}; // 昇順
int idx = Arrays.binarySearch(names, "Carol"); // 2
Java- 注意: 比較は自然順序。ロケールに配慮した文字列比較が必要なら、ソート時点で
Collatorを使うなどの工夫を行います。
よくある落とし穴と回避策
- 未ソートでの検索: ソートせずに
binarySearch→ 誤結果。- 回避: 必ず
Arrays.sort実行後にbinarySearch。
- 回避: 必ず
- プリミティブ降順の比較指定不可:
int[]にComparatorは渡せません。- 回避:
Integer[]に変換してソート、または昇順後に反転。
- 回避:
- 挿入位置の負値規則を誤解: 負値は単なる「見つからない」ではなく「挿入位置情報」。
- 回避:
insertionPoint = -pos - 1を必ず適用。
- 回避:
- 固定長ゆえの挿入不可: 配列は長さ変更できない。
- 回避: 追加・挿入が必要なら
ArrayListに移行、またはArrays.copyOfでサイズを増やして末尾へ追加。
- 回避: 追加・挿入が必要なら
便利ユーティリティ(覚えておくと楽)
- 配列の文字列化:
Arrays.toString(arr)/ 多次元はArrays.deepToString(arr2d) - サイズ変更コピー:
Arrays.copyOf(arr, newLen)/ 範囲コピーはArrays.copyOfRange(arr, from, to) - 等価性・ハッシュ: 多次元は
Arrays.deepEquals/Arrays.deepHashCode
例題で身につける
例題1: 点数を昇順に並べてターゲットを高速検索
int[] scores = {72, 88, 90, 65, 99, 80};
Arrays.sort(scores); // [65, 72, 80, 88, 90, 99]
int pos = Arrays.binarySearch(scores, 88); // 3
System.out.println(pos >= 0 ? "見つかった: index=" + pos : "未検出");
Java- ねらい: ソート→二分探索の基本パターンを体得。
例題2: 文字列配列の検索と挿入位置算出
String[] cities = {"Chiba", "Kyoto", "Osaka", "Tokyo"};
Arrays.sort(cities); // [Chiba, Kyoto, Osaka, Tokyo]
int pos = Arrays.binarySearch(cities, "Kobe"); // 未検出 → 負の値
int ins = (pos >= 0) ? pos : -pos - 1; // 挿入位置
System.out.println("Kobe の挿入位置 = " + ins);
Java- ねらい: 負値規則から挿入位置を導く練習。
例題3: オブジェクト配列の複合キーソート
class Product {
final String name; final int price;
Product(String n, int p) { name = n; price = p; }
public String toString(){ return name + "(" + price + ")"; }
}
Product[] ps = { new Product("Tea", 300), new Product("Coffee", 500), new Product("Cake", 500) };
Arrays.sort(ps,
java.util.Comparator.comparingInt((Product p) -> p.price) // 価格昇順
.thenComparing(p -> p.name)); // 同価格は名前昇順
System.out.println(Arrays.toString(ps)); // [Tea(300), Cake(500), Coffee(500)]
Java- ねらい:
Comparatorで業務ロジックに沿った並び替え。
テンプレート集
- 昇順ソート(プリミティブ)
Arrays.sort(arr);
Java- 降順ソート(参照型)
Arrays.sort(arr, Comparator.reverseOrder());
Java- 二分探索+挿入位置
int pos = Arrays.binarySearch(arr, key);
int insertionPoint = (pos >= 0) ? pos : -pos - 1;
Java- コピー/範囲コピー
T[] copy = Arrays.copyOf(arr, newLen);
T[] part = Arrays.copyOfRange(arr, from, to); // [from, to)
Javaまとめ
- 配列の検索は「ソートしてから
binarySearch」が基本。見つからないときの返り値は「挿入位置を表す負値」なので必ず解釈する。sortはプリミティブも参照型も対応、参照型はComparatorで柔軟に並べ替えられる。配列は固定長なので、挿入・追加が必要ならコピーやリストへ移行するのが現実的です。
