Array.Sortの標準動作とその限界
Array.Sort(array)メソッドは、配列の要素を「昇順」に並べ替えるための非常に便利な静的メソッドです。
int型なら数値の小さい順(1, 5, 10)string型なら辞書順("A", "B", "C")
しかし、もし「文字列を長さの短い順に並べ替えたい」や、「数値を絶対値の小さい順に並べ替えたい」といった、デフォルト以外の独自の(カスタム)ルールでソートしたい場合、Array.Sort(array)だけでは対応できません。
このような場合、Array.Sortのオーバーロード(引数が異なる同名メソッド)に、Comparison<T>デリゲート(比較メソッド)を渡すことで、ソートロジックを自由に定義できます。
Comparison<T> デリゲートとは
Comparison<T>は、2つの同じ型(T)のオブジェクト(aとb)を受け取り、それらの大小関係をint(整数)で返すメソッドの「型」を定義するデリゲートです。
戻り値のルール: Comparison<T>デリゲート(またはラムダ式)は、以下のルールに従ってint型の値を返す必要があります。
- 負の値(
0未満):aはbよりも小さい(aをbよりも前に並べる)。 - ゼロ(
0):aとbは等しい(順序は問わない)。 - 正の値(
0より大きい):aはbよりも大きい(aをbよりも後に並べる)。
このルールは、int型やstring型が持つCompareToメソッドの戻り値と一致しています。
コード例1:string配列を「長さ順」でソート(昇順・降順)
Array.Sortの第2引数に、この比較ルールを実装した「ラムダ式」を渡すのが最も一般的な方法です。
CompareToメソッドを活用すると、このロジックを簡単に実装できます。
using System;
public class SortByLengthExample
{
public static void Main()
{
string[] fileNames = { "report-2025.pdf", "data.csv", "summary.txt", "archive.zip" };
Console.WriteLine("--- 元の順序 ---");
PrintArray(fileNames);
// --- 1. 昇順(長さの短い順)でソート ---
// (a, b) => a.Length.CompareTo(b.Length)
// a.Length が b.Length より短ければ負、長ければ正が返る
Array.Sort(fileNames, (a, b) => a.Length.CompareTo(b.Length));
Console.WriteLine("\n--- 長さ昇順 (短い順) ---");
PrintArray(fileNames);
// --- 2. 降順(長さの長い順)でソート ---
// (a, b) => b.Length.CompareTo(a.Length)
// a と b の比較ロジックを逆転させる
Array.Sort(fileNames, (a, b) => b.Length.CompareTo(a.Length));
Console.WriteLine("\n--- 長さ降順 (長い順) ---");
PrintArray(fileNames);
}
private static void PrintArray(string[] arr)
{
foreach (var item in arr)
{
Console.WriteLine(item);
}
}
}
出力結果:
--- 元の順序 ---
report-2025.pdf
data.csv
summary.txt
archive.zip
--- 長さ昇順 (短い順) ---
data.csv
summary.txt
archive.zip
report-2025.pdf
--- 長さ降順 (長い順) ---
report-2025.pdf
archive.zip
summary.txt
data.csv
コード例2:int配列を「絶対値」でソート
この手法は、string型だけでなく、あらゆる型の配列に適用できます。int配列を、数値の大小ではなく「絶対値(0からの距離)」で並べ替える例です。
using System;
public class SortByAbsoluteValueExample
{
public static void Main()
{
int[] numbers = { 10, -50, 2, -100, 30 };
Console.WriteLine("--- 元の順序 ---");
PrintArray(numbers);
// Math.Abs() で絶対値を取得し、それを比較する
Array.Sort(numbers, (a, b) => Math.Abs(a).CompareTo(Math.Abs(b)));
Console.WriteLine("\n--- 絶対値の昇順 ---");
PrintArray(numbers); // 2, 10, 30, -50, -100 (の順)
}
private static void PrintArray(int[] arr)
{
foreach (var item in arr) Console.Write($"[{item}] ");
Console.WriteLine();
}
}
出力結果:
--- 元の順序 ---
[10] [-50] [2] [-100] [30]
--- 絶対値の昇順 ---
[2] [10] [30] [-50] [-100]
(注: 2 (絶対値2) が -100 (絶対値100) より先に来ています。)
補足:Comparison<T>デリゲート変数
もし比較ロジックが複雑で、ラムダ式では読みにくい場合、ロジックをComparison<T>デリゲート型の変数として切り出すことができます。
using System;
public class SortWithDelegateExample
{
public static void Main()
{
string[] fileNames = { "report-2025.pdf", "data.csv", "summary.txt" };
// 比較ロジックをデリゲート変数に格納
Comparison<string> lengthComparer = (a, b) => a.Length.CompareTo(b.Length);
// Sort メソッドにその変数を渡す
Array.Sort(fileNames, lengthComparer);
foreach (var item in fileNames)
{
Console.WriteLine(item);
}
}
}
まとめ
Array.Sortメソッドの第2引数にComparison<T>デリゲート(通常はラムダ式)を渡すことで、配列の並べ替えルールを自由に定義(カスタマイズ)できます。
比較ロジックは「aがbより先なら負、後なら正」という規約に従う必要がありますが、CompareToメソッドを利用することで、昇順・降順のロジックを簡潔かつ安全に記述できます。
