C#のSort完全ガイド|List・配列の昇順/降順ソートから独自条件の並び替えまで
はじめに
C#でデータを扱う際、要素を昇順や降順に並び替える「ソート」は非常に頻繁に使われる処理です。数値や文字列、日付などの基本的なソートから、独自の条件で並び替えるカスタムソートまで、C#には多彩な方法が用意されています。本記事では、Listや配列、LINQを使ったソート方法を網羅的に解説し、実務で役立つテクニックまで紹介します。
1. C#のSortでできること|まず押さえるべき並び替えの基本
1-1. C#におけるSortとは何か
C#のSortは、コレクション内の要素を特定の順序に並び替えるメソッドです。既存のデータ構造を直接書き換える「破壊的ソート」と呼ばれる特徴があります。Listや配列、LINQのOrderByなど、目的に応じて使い分けることが可能です。
1-2. 昇順ソートと降順ソートの違い
昇順ソート:小さい値から大きい値、アルファベット順ならA→Z、日付なら古い順。
降順ソート:大きい値から小さい値、Z→A、日付なら新しい順。
ソート方法の選択は、データの並べ替え目的に応じて決めます。
1-3. List・配列・LINQで使うソート方法の違い
List<T>.Sort():リストを破壊的に並び替え。
Array.Sort():配列の要素を破壊的に並び替え。
LINQのOrderBy / OrderByDescending:非破壊的に並び替え、新しいコレクションを返す。
1-4. SortとOrderByの使い分け早見表
| メソッド | 破壊的か | 戻り値 | 利点 |
|---|---|---|---|
| List.Sort() | はい | void | シンプルで高速 |
| Array.Sort() | はい | void | 配列専用、高速 |
| OrderBy / OrderByDescending | いいえ | IEnumerable<T> | 元データ保持、LINQチェーン可能 |
2. ListをSortで昇順に並び替える基本
2-1. List.Sort()の基本構文
C#List<int> numbers = new List<int> {3, 1, 4, 2};
numbers.Sort();
これだけでリストが昇順に並び替えられます。
2-2. 数値のListを昇順にソートする
整数や小数のリストは、Sort()を呼ぶだけで自然な数値順に並びます。
2-3. 文字列のListを昇順にソートする
文字列もSort()でアルファベット順に並び替え可能です。日本語の場合はカルチャに注意する必要があります。
2-4. DateTimeのListを日付順にソートする
C#List<DateTime> dates = new List<DateTime> { DateTime.Now, DateTime.Now.AddDays(-1) };
dates.Sort();
日付が古い順に並びます。
2-5. List.Sort()は元のList自体を並び替える点に注意
Sort()はリストを直接書き換えるため、元の順序を保持したい場合はコピーを作る必要があります。
3. Listを降順に並び替える方法
3-1. Sort後にReverse()で降順にする
C#numbers.Sort();
numbers.Reverse();
簡単ですが、二度処理が発生します。
3-2. Comparisonを使って降順ソートする
C#numbers.Sort((a, b) => b.CompareTo(a));
直接降順にソートできます。
3-3. LINQのOrderByDescendingで降順にする
C#var descendingNumbers = numbers.OrderByDescending(n => n).ToList();
元のリストを保持しつつ新しいリストを作成可能です。
3-4. 降順ソートでよくあるミスと対処法
元データを直接変更してしまう
nullや空文字の扱いで例外が発生
文字列の大文字・小文字で思った順にならない
対策として、nullチェックやカルチャ設定を利用します。
4. 配列をArray.Sortで並び替える方法
4-1. Array.Sort()の基本構文
C#int[] array = {3, 1, 4, 2};
Array.Sort(array);
配列の要素が昇順に並びます。
4-2. int配列を昇順にソートする
整数配列はArray.Sort()で簡単に昇順に並べ替えられます。
4-3. string配列を昇順にソートする
文字列配列もArray.Sort()でアルファベット順に並べ替え可能。日本語はStringComparerを指定すると自然な順序に。
4-4. 配列を降順にソートする
C#Array.Sort(array);
Array.Reverse(array);
またはArray.Sort(array, (a,b) => b.CompareTo(a));で直接降順も可能。
4-5. Array.SortとList.Sortの違い
配列専用かリスト専用か
両方とも破壊的
LINQとの相性や拡張性の違い
5. オブジェクトのListをプロパティでソートする
5-1. クラスや構造体のListをソートする考え方
オブジェクトの特定プロパティで並び替える場合、Comparison<T>やOrderByでプロパティを指定します。
5-2. 年齢・価格・スコアなど数値プロパティで並び替える
C#users.Sort((a,b) => a.Age.CompareTo(b.Age));
5-3. 名前など文字列プロパティで並び替える
C#users.Sort((a,b) => string.Compare(a.Name, b.Name));
5-4. 日付プロパティで新しい順・古い順に並び替える
C#users.Sort((a,b) => b.JoinDate.CompareTo(a.JoinDate));
5-5. nullを含むプロパティを安全にソートする方法
C#users.Sort((a,b) => (a.Name ?? "").CompareTo(b.Name ?? ""));
nullを空文字に置き換えることで例外を回避。
6. 独自条件で並び替えるカスタムソート
6-1. Comparison<T>を使ったカスタムソート
C#list.Sort((x, y) => x.Score - y.Score);
複雑な条件でも一つのラムダで定義可能。
6-2. ラムダ式で簡潔に比較条件を書く
数値や文字列の複数条件も短く記述可能です。
6-3. IComparer<T>を使って比較ロジックを分離する
独自のクラスで比較をまとめ、再利用性を高められます。
6-4. IComparable<T>を実装してデフォルトの並び順を定義する
クラス自体に並び順を定義することで、Sort()だけで自然順序に並べ替え可能です。
6-5. 特定の順番を指定して並び替える方法
優先度リストやカスタム順序を事前に定義し、比較関数で参照する方法があります。
7. LINQでソートするOrderBy・ThenByの使い方
7-1. OrderByで昇順に並び替える
C#var sorted = users.OrderBy(u => u.Age).ToList();
7-2. OrderByDescendingで降順に並び替える
C#var sortedDesc = users.OrderByDescending(u => u.Age).ToList();
7-3. ThenByで複数条件のソートを行う
C#var sorted = users.OrderBy(u => u.Age).ThenBy(u => u.Name).ToList();
7-4. ThenByDescendingを組み合わせる
数値は昇順、名前は降順など柔軟に指定可能です。
7-5. ToList()やToArray()が必要になるケース
LINQはIEnumerable<T>を返すため、リストや配列に変換する場合はToList()やToArray()を使用します。
8. SortとOrderByの違いを理解する
8-1. Sortは破壊的ソート、OrderByは非破壊的ソート
元のデータを変更するか、新しいコレクションを作るかの違いです。
8-2. 戻り値の違い
Sort():voidOrderBy():IEnumerable<T>
8-3. パフォーマンス面の違い
小規模データは差が少ないですが、大規模データではSort()の方が高速な場合があります。
8-4. 実務ではどちらを使うべきか
元データを保持したい場合はOrderBy、直接書き換えて高速化したい場合はSortがおすすめです。
8-5. 元データを保持したい場合の書き方
C#var newList = oldList.OrderBy(x => x.Value).ToList();
9. 実務でよく使うC#ソートの実例
9-1. ユーザー一覧を名前順に並び替える
C#users.Sort((a,b) => string.Compare(a.Name, b.Name));
9-2. 商品一覧を価格の安い順・高い順に並び替える
C#products.Sort((a,b) => a.Price.CompareTo(b.Price)); // 安い順
products.Sort((a,b) => b.Price.CompareTo(a.Price)); // 高い順
9-3. ランキングをスコア順に並び替える
スコアが高い順にSort((a,b) => b.Score.CompareTo(a.Score))で並べます。
9-4. 更新日時の新しい順に並び替える
DateTimeプロパティを使って降順ソート。
9-5. 複数条件で一覧表示を並び替える
LINQのOrderBy().ThenBy()で複数条件を組み合わせ、実務でよく使われます。
10. C#のSortでつまずきやすい注意点
10-1. Sort()の戻り値を代入しようとしてエラーになる
Sort()はvoidなので、代入は不要です。
10-2. 文字列ソートで大文字・小文字や日本語の順序が想定と違う
StringComparer.OrdinalIgnoreCaseやカルチャを指定することで対応可能。
10-3. nullを含むデータで例外や不自然な並び順になる
??演算子でnullを置き換えることで安全にソート可能です。
10-4. 独自クラスで比較方法を指定せずにSortして失敗する
IComparableやComparisonを実装しておくことが重要です。
10-5. 安定ソートが必要な場合の考え方
Sort()は安定ソートではないため、順序保持が必要な場合はOrderByを使うのがおすすめです。
11. C# Sortのよくある質問
11-1. List.Sort()で降順にする一番簡単な方法は?
C#numbers.Sort();
numbers.Reverse();
11-2. 配列を降順にソートするには?
C#Array.Sort(array);
Array.Reverse(array);
または比較関数で直接降順に指定可能。
11-3. オブジェクトを複数条件でソートするには?
LINQのOrderBy().ThenBy()またはSort()でComparisonを組み合わせます。
11-4. SortとOrderByはどちらが速い?
小規模は差が少ないですが、大規模データではSort()が高速な場合があります。
11-5. 元のListを変更せずに並び替えるには?
C#var newList = oldList.OrderBy(x => x.Value).ToList();
まとめ
C#のソートは、List.Sort()やArray.Sort()での破壊的ソートと、LINQのOrderBy/OrderByDescendingでの非破壊的ソートに大別されます。昇順・降順の基本から、オブジェクトのプロパティや独自条件でのカスタムソートまで幅広く対応可能です。実務では、元データを保持したい場合や複数条件で並び替えたい場合など、状況に応じて適切な方法を選ぶことが重要です。

