はじめに
C#で使用するソート系メソッドをまとめました。
個人的な備忘録です。間違いなどあれば教えていただけると嬉しいです。
必要なusing文
using System; // Array.Sort用
using System.Collections.Generic; // List<T>用
using System.Linq; // OrderBy, Where, Select用
配列のソート
Array.Sort() - 破壊的
int[] array = { 5, 2, 8, 1, 9 };
Array.Sort(array); // 元の配列が変更される
// 結果: { 1, 2, 5, 8, 9 }
OrderBy() - 非破壊的
int[] array = { 5, 2, 8, 1, 9 };
var sorted = array.OrderBy(x => x).ToArray();
// 元の配列: { 5, 2, 8, 1, 9 } (変更されない)
// sorted: { 1, 2, 5, 8, 9 }
元データを保持したい場合
int[] original = { 5, 2, 8, 1, 9 };
// 方法1: Clone()を使用
int[] copy = (int[])original.Clone();
Array.Sort(copy);
// 方法2: OrderBy()を使用
var sorted = original.OrderBy(x => x).ToArray();
Listのソート
List.Sort() - 破壊的
var list = new List<int> { 5, 2, 8, 1, 9 };
list.Sort(); // 元のリストが変更される
// 結果: { 1, 2, 5, 8, 9 }
OrderBy() - 非破壊的
var list = new List<int> { 5, 2, 8, 1, 9 };
var sorted = list.OrderBy(x => x).ToList();
// 元のリスト: { 5, 2, 8, 1, 9 } (変更されない)
// sorted: { 1, 2, 5, 8, 9 }
カスタムソート
var list = new List<int> { 5, 2, 8, 1, 9 };
// 降順
list.Sort((x, y) => y.CompareTo(x));
// 絶対値でソート
list.Sort((x, y) => Math.Abs(x).CompareTo(Math.Abs(y)));
LINQ基本メソッド
OrderBy() / OrderByDescending()
var numbers = new List<int> { 5, 2, 8, 1, 9 };
var asc = numbers.OrderBy(x => x); // 昇順
var desc = numbers.OrderByDescending(x => x); // 降順
ThenBy() / ThenByDescending()
var people = new List<(string Name, int Age)>
{
("田中", 25), ("佐藤", 25), ("鈴木", 30)
};
var sorted = people
.OrderBy(x => x.Age) // まず年齢でソート
.ThenBy(x => x.Name) // 同じ年齢なら名前でソート
.ToList();
Where() - フィルタリング
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var evenNumbers = numbers.Where(x => x % 2 == 0); // 偶数のみ
var greaterThan5 = numbers.Where(x => x > 5); // 5より大きい
var range = numbers.Where(x => x >= 3 && x <= 7); // 3以上7以下
Select() - 変換
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var doubled = numbers.Select(x => x * 2); // 2倍
var strings = numbers.Select(x => $"数字{x}"); // 文字列変換
var squared = numbers.Select(x => x * x); // 平方
Reverse() - 順序逆転
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var reversed = numbers.Reverse(); // 逆順
タプルのソート
基本的なタプルソート
var dates = new List<(int Month, int Day)>
{
(3, 29), (1, 1), (1, 4), (12, 28), (4, 1)
};
// 月→日の順でソート
var sorted = dates.OrderBy(x => x.Month).ThenBy(x => x.Day).ToList();
// 結果: (1,1), (1,4), (3,29), (4,1), (12,28)
複雑なタプルソート
var people = new List<(string Name, int Age, string City)>
{
("田中", 25, "東京"), ("佐藤", 30, "大阪"), ("鈴木", 25, "東京")
};
// 年齢→名前の順でソート
var sorted = people.OrderBy(x => x.Age).ThenBy(x => x.Name).ToList();
// 都市→年齢→名前の順でソート
var multiSort = people
.OrderBy(x => x.City)
.ThenBy(x => x.Age)
.ThenBy(x => x.Name)
.ToList();
4月2日から始まる年間カレンダーソート
var dates = new List<(int Month, int Day)>
{
(3, 29), (1, 1), (1, 4), (12, 28), (4, 1), (4, 2)
};
// 4月2日を基準とした並び順
var yearFromApril = dates.OrderBy(x =>
{
if (x.Month > 4 || (x.Month == 4 && x.Day >= 2))
return x.Month * 100 + x.Day; // 今年(ソート用キー値)
else
return (x.Month + 12) * 100 + x.Day; // 翌年扱い(ソート用キー値)
// ※この計算はソート順を決めるためだけで、元のタプルは変更されない
}).ToList();
// 結果: (4,2), (12,28), (1,1), (1,4), (3,29), (4,1)
メソッドチェーン
var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var result = numbers
.Where(x => x % 2 == 0) // 偶数のみ
.Select(x => x * 3) // 3倍
.OrderByDescending(x => x) // 降順
.Take(3) // 上位3つ
.ToList();
// 結果: { 30, 24, 18 }
ソート後の比較
var list1 = new List<int> { 5, 2, 8, 1, 9 };
var list2 = new List<int> { 1, 2, 5, 8, 9 };
// == では比較できない(参照比較のため)
Console.WriteLine(list1 == list2); // False(中身が同じでも異なるインスタンス)
// SequenceEqual で順序も含めて比較
Console.WriteLine(list1.SequenceEqual(list2)); // False(順序が違う)
// 先にソートしてから比較(順序無視で要素を比較)
var sortedList1 = list1.OrderBy(x => x).ToList();
var sortedList2 = list2.OrderBy(x => x).ToList();
var areEqualWhenSorted = sortedList1.SequenceEqual(sortedList2);
Console.WriteLine(areEqualWhenSorted); // True
使い分けガイド
元データを変更してもよい場合
-
配列:
Array.Sort() -
List:
list.Sort()
元データを保持したい場合
-
配列:
array.OrderBy(x => x).ToArray() -
List:
list.OrderBy(x => x).ToList()
複雑な条件でソート
-
共通:
OrderBy()+ThenBy()
Dictionaryのソート
var dict = new Dictionary<string, int> { {"a", 3}, {"b", 1}, {"c", 2} };
var sortedByKey = dict.OrderBy(x => x.Key); // キーでソート
var sortedByValue = dict.OrderBy(x => x.Value); // 値でソート
注意点
破壊的メソッド(元データ変更)
Array.Sort()List.Sort()List.Reverse()Array.Reverse()
非破壊的メソッド(元データ保持)
-
OrderBy()系 Where()Select()-
Reverse()(LINQ版)
OrderbyやWhereなどは遅延実行される
var query = numbers.Where(x => x > 5); // まだ実行されない
var result = query.ToList(); // ここで実行される
よく使うパターン
年齢でソート、同じ年齢なら名前順
people.OrderBy(p => p.Age).ThenBy(p => p.Name)
偶数のみ取得して降順ソート
numbers.Where(x => x % 2 == 0).OrderByDescending(x => x)
名前を取得してアルファベット順
people.Select(p => p.Name).OrderBy(name => name)
上位3件を取得
numbers.OrderByDescending(x => x).Take(3)
対応表
| コレクション | Sort() | OrderBy() | 専用メソッド |
|---|---|---|---|
| int[] | ❌ | ✅ | Array.Sort() |
| List | ✅ | ✅ | - |
| Dictionary | ❌ | ✅ | - |
| 配列・リスト以外※ | ❌ | ✅ | - |
※IEnumerableを実装する型(HashSet、Queue、Stack等)