C#のListをSortで並び替える方法|昇順・降順・条件指定までわかりやすく解説

はじめに

C#で複数のデータを扱うとき、List<T>を並び替えたい場面はよくあります。たとえば、数値を小さい順に並べる、文字列を名前順に並べる、商品一覧を価格順に並べる、ユーザー一覧を年齢順に並べる、といった処理です。

C#のListをソートする代表的な方法が、List.Sortメソッドです。Sortを使うと、intstringDateTimeのような基本的な型だけでなく、独自クラスのオブジェクトも条件を指定して並び替えられます。

この記事では、csharp list sortで知りたい内容として、List.Sortの基本、昇順・降順の書き方、ラムダ式を使った条件指定、オブジェクトのプロパティによるソート、IComparer、LINQのOrderByとの違いまで、サンプルコード付きでわかりやすく解説します。

1. C#のList.Sortとは?まず押さえる基本

1-1. List.Sortでできること

List.Sortは、C#のList<T>に格納されている要素を並び替えるためのメソッドです。List<T>は、要素の検索・並び替え・操作を行える汎用リストで、Sortメソッドを使うとリスト内の要素を指定した順序に並べ替えられます。

たとえば、次のような処理ができます。

C#
List<int> numbers = new List<int> { 3, 1, 5, 2, 4 };

numbers.Sort();

Console.WriteLine(string.Join(", ", numbers));
// 出力: 1, 2, 3, 4, 5

Sort()を呼び出すだけで、intのリストは小さい順、つまり昇順に並び替えられます。

1-2. Sortは元のListを直接並び替える

List.Sortで重要なのは、元のListそのものを直接変更するという点です。これは「破壊的な並び替え」や「インプレースソート」と呼ばれる考え方です。

C#
List<int> numbers = new List<int> { 3, 1, 2 };

numbers.Sort();

Console.WriteLine(string.Join(", ", numbers));
// 出力: 1, 2, 3

Sort()を実行した後、numbersの中身はすでに並び替わっています。つまり、並び替え後の新しいリストが返ってくるわけではありません。

次のような書き方はできないため注意しましょう。

C#
// NG: Sortは並び替えたListを返さない
// var sortedNumbers = numbers.Sort();

Sortの戻り値はvoidです。並び替え後のリストは、元の変数をそのまま使います。

1-3. Sortを使うための基本構文

List.Sortの基本構文は次の通りです。

C#
list.Sort();

条件を指定したい場合は、ラムダ式を渡します。

C#
list.Sort((a, b) => a.CompareTo(b));

オブジェクトのプロパティで並び替えたい場合は、次のように書けます。

C#
people.Sort((a, b) => a.Age.CompareTo(b.Age));

Sortには複数のオーバーロードがあり、引数なしのSort()、比較処理を渡すSort(Comparison<T>)、比較用クラスを渡すSort(IComparer<T>)などが用意されています。

1-4. SortとArray.Sortの違い

List.SortList<T>を並び替えるためのメソッドで、Array.Sortは配列を並び替えるためのメソッドです。どちらもC#でよく使われるソート方法ですが、対象が異なります。

C#
// Listの場合
List<int> list = new List<int> { 3, 1, 2 };
list.Sort();

// 配列の場合
int[] array = { 3, 1, 2 };
Array.Sort(array);

List<T>を使っているならlist.Sort()、配列を使っているならArray.Sort(array)を使う、と考えるとわかりやすいです。Array.Sortには、キー配列と値配列を関連付けて並び替えるオーバーロードなど、配列向けの機能も用意されています。

2. Listを昇順に並び替える方法

2-1. 数値のListを昇順にソートする

数値のListを昇順に並び替える場合は、Sort()を呼び出すだけです。

C#
List<int> scores = new List<int> { 80, 50, 100, 70, 90 };

scores.Sort();

Console.WriteLine(string.Join(", ", scores));
// 出力: 50, 70, 80, 90, 100

intは標準で大小比較ができる型なので、特別な条件を指定しなくても小さい順に並び替えられます。

doubledecimalなどの数値型でも、基本的な考え方は同じです。

C#
List<double> prices = new List<double> { 19.8, 10.5, 30.0, 25.3 };

prices.Sort();

Console.WriteLine(string.Join(", ", prices));
// 出力: 10.5, 19.8, 25.3, 30

2-2. 文字列のListを昇順にソートする

文字列のListSort()で並び替えられます。

C#
List<string> names = new List<string> { "Taro", "Hanako", "Jiro", "Akira" };

names.Sort();

Console.WriteLine(string.Join(", ", names));
// 出力例: Akira, Hanako, Jiro, Taro

アルファベットの文字列であれば、辞書順のような形で並び替えられます。

日本語の文字列もソートできます。

C#
List<string> fruits = new List<string> { "みかん", "りんご", "いちご", "ぶどう" };

fruits.Sort();

Console.WriteLine(string.Join(", ", fruits));

ただし、文字列の並び順はカルチャや比較方法の影響を受ける場合があります。大文字・小文字を無視したい場合や、厳密な文字コード順で比較したい場合は、後述するStringComparerを使う方法が便利です。

2-3. DateTimeのListを昇順にソートする

DateTimeListSort()で古い日付から新しい日付へ並び替えられます。

C#
List<DateTime> dates = new List<DateTime>
{
new DateTime(2025, 5, 1),
new DateTime(2024, 12, 10),
new DateTime(2026, 1, 15)
};

dates.Sort();

foreach (var date in dates)
{
Console.WriteLine(date.ToString("yyyy-MM-dd"));
}

出力結果は次のようになります。

2024-12-10
2025-05-01
2026-01-15

予定一覧、予約日時、更新日時などを古い順に並べたい場合に使えます。

2-4. Sort後の結果を確認するサンプルコード

Sort後の結果を確認するときは、foreachstring.Joinを使うと簡単です。

C#
List<int> numbers = new List<int> { 5, 2, 8, 1, 3 };

Console.WriteLine("ソート前:");
Console.WriteLine(string.Join(", ", numbers));

numbers.Sort();

Console.WriteLine("ソート後:");
Console.WriteLine(string.Join(", ", numbers));

出力結果です。

ソート前:
5, 2, 8, 1, 3
ソート後:
1, 2, 3, 5, 8

このように、Sort()を呼び出した時点で元のListが並び替わっていることがわかります。

3. Listを降順に並び替える方法

3-1. SortとReverseを組み合わせて降順にする

もっとも簡単に降順へ並び替える方法は、Sort()で昇順にしたあと、Reverse()で反転する方法です。

C#
List<int> numbers = new List<int> { 3, 1, 5, 2, 4 };

numbers.Sort();
numbers.Reverse();

Console.WriteLine(string.Join(", ", numbers));
// 出力: 5, 4, 3, 2, 1

この方法は直感的で読みやすいため、初心者にもおすすめです。

文字列でも同じように使えます。

C#
List<string> names = new List<string> { "Taro", "Hanako", "Jiro", "Akira" };

names.Sort();
names.Reverse();

Console.WriteLine(string.Join(", ", names));
// 出力例: Taro, Jiro, Hanako, Akira

3-2. ラムダ式で降順にソートする

Sortにラムダ式を渡すと、直接降順に並び替えられます。

C#
List<int> numbers = new List<int> { 3, 1, 5, 2, 4 };

numbers.Sort((a, b) => b.CompareTo(a));

Console.WriteLine(string.Join(", ", numbers));
// 出力: 5, 4, 3, 2, 1

ポイントは、a.CompareTo(b)ではなくb.CompareTo(a)にすることです。

昇順の場合は次のように書きます。

C#
numbers.Sort((a, b) => a.CompareTo(b));

降順の場合は比較対象を逆にします。

C#
numbers.Sort((a, b) => b.CompareTo(a));

3-3. CompareToを使って安全に降順指定する

降順に並び替えるときは、CompareToを使う書き方が安全です。

C#
List<int> numbers = new List<int> { int.MaxValue, 0, int.MinValue };

numbers.Sort((a, b) => b.CompareTo(a));

Console.WriteLine(string.Join(", ", numbers));
// 出力: 2147483647, 0, -2147483648

CompareToは、比較結果として負の値、0、正の値を返します。Sortはこの戻り値をもとに要素の順序を決めます。比較処理を渡すSort(Comparison<T>)では、比較用の関数を使って要素同士の順序を決定します。

3-4. b - aで比較する書き方の注意点

降順ソートの例として、次のようなコードを見かけることがあります。

C#
numbers.Sort((a, b) => b - a);

一見シンプルですが、この書き方には注意が必要です。intの値が非常に大きい場合、b - aの計算でオーバーフローが起きる可能性があります。

たとえば、int.MaxValueint.MinValueを含む場合は危険です。

C#
List<int> numbers = new List<int> { int.MaxValue, int.MinValue };

numbers.Sort((a, b) => b - a); // オーバーフローの可能性

安全に書くなら、次のようにCompareToを使いましょう。

C#
numbers.Sort((a, b) => b.CompareTo(a));

4. 条件を指定してListをソートする方法

4-1. Sortにラムダ式を渡して並び替える

Sortにラムダ式を渡すと、独自の条件で並び替えられます。

C#
List<string> words = new List<string> { "apple", "banana", "kiwi", "orange" };

words.Sort((a, b) => a.Length.CompareTo(b.Length));

Console.WriteLine(string.Join(", ", words));
// 出力: kiwi, apple, banana, orange

この例では、文字列の長さが短い順に並び替えています。

長い順にしたい場合は、比較を逆にします。

C#
words.Sort((a, b) => b.Length.CompareTo(a.Length));

Console.WriteLine(string.Join(", ", words));
// 出力例: banana, orange, apple, kiwi

4-2. 偶数・奇数など独自条件で並び替える

偶数を先、奇数を後に並び替えることもできます。

C#
List<int> numbers = new List<int> { 5, 2, 8, 1, 3, 4 };

numbers.Sort((a, b) =>
{
int aGroup = a % 2;
int bGroup = b % 2;

int groupCompare = aGroup.CompareTo(bGroup);
if (groupCompare != 0)
{
return groupCompare;
}

return a.CompareTo(b);
});

Console.WriteLine(string.Join(", ", numbers));
// 出力: 2, 4, 8, 1, 3, 5

このコードでは、まず偶数か奇数かで比較し、同じグループ内では数値の昇順で並べています。

処理の考え方は次の通りです。

偶数 → 先に表示
奇数 → 後に表示
同じ偶数同士・奇数同士 → 小さい順

4-3. nullを含むListを安全にソートする

文字列のListnullが含まれる場合、比較処理で例外が発生しないように注意が必要です。

C#
List<string?> names = new List<string?> { "Taro", null, "Hanako", "Jiro" };

names.Sort((a, b) =>
{
if (a == null && b == null) return 0;
if (a == null) return -1;
if (b == null) return 1;

return a.CompareTo(b);
});

Console.WriteLine(string.Join(", ", names.Select(x => x ?? "null")));
// 出力例: null, Hanako, Jiro, Taro

この例では、nullを先頭に並べています。

nullを最後にしたい場合は、条件を逆にします。

C#
names.Sort((a, b) =>
{
if (a == null && b == null) return 0;
if (a == null) return 1;
if (b == null) return -1;

return a.CompareTo(b);
});

4-4. 大文字・小文字を無視して文字列をソートする

大文字・小文字を無視してソートしたい場合は、StringComparer.OrdinalIgnoreCaseを使うとわかりやすいです。

C#
List<string> words = new List<string> { "banana", "Apple", "cherry", "apple" };

words.Sort(StringComparer.OrdinalIgnoreCase);

Console.WriteLine(string.Join(", ", words));
// 出力例: Apple, apple, banana, cherry

ラムダ式で書く場合は、次のようにも書けます。

C#
words.Sort((a, b) => string.Compare(a, b, StringComparison.OrdinalIgnoreCase));

大文字と小文字を区別したくない検索結果や、ユーザー名の一覧を並び替えるときに便利です。

5. オブジェクトのListをプロパティでソートする方法

5-1. クラスのListをSortで並び替える基本

実務では、intstringだけでなく、独自クラスのListを並び替えることが多くあります。

たとえば、次のようなPersonクラスがあるとします。

C#
class Person
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
}

このPersonのリストを年齢順に並び替えるには、Sortに比較条件を渡します。

C#
List<Person> people = new List<Person>
{
new Person { Id = 3, Name = "Taro", Age = 30 },
new Person { Id = 1, Name = "Hanako", Age = 25 },
new Person { Id = 2, Name = "Jiro", Age = 20 }
};

people.Sort((a, b) => a.Age.CompareTo(b.Age));

foreach (var person in people)
{
Console.WriteLine($"{person.Name}: {person.Age}");
}

出力結果です。

Jiro: 20
Hanako: 25
Taro: 30

5-2. 年齢・IDなど数値プロパティでソートする

数値プロパティでソートする場合は、CompareToを使うのが基本です。

C#
people.Sort((a, b) => a.Id.CompareTo(b.Id));

降順にしたい場合は、比較対象を逆にします。

C#
people.Sort((a, b) => b.Id.CompareTo(a.Id));

年齢の若い順にする場合です。

C#
people.Sort((a, b) => a.Age.CompareTo(b.Age));

年齢の高い順にする場合です。

C#
people.Sort((a, b) => b.Age.CompareTo(a.Age));

数値プロパティのソートでは、a.Id - b.Idのような引き算ではなく、CompareToを使うと安全です。

5-3. 名前など文字列プロパティでソートする

文字列プロパティでソートする場合も、CompareTostring.Compareを使います。

C#
people.Sort((a, b) => a.Name.CompareTo(b.Name));

大文字・小文字を無視したい場合は、次のように書けます。

C#
people.Sort((a, b) => string.Compare(
a.Name,
b.Name,
StringComparison.OrdinalIgnoreCase
));

Namenullになる可能性がある場合は、string.Compareを使うと比較的扱いやすくなります。

C#
people.Sort((a, b) => string.Compare(
a.Name,
b.Name,
StringComparison.OrdinalIgnoreCase
));

ただし、プロパティ自体がnull許容の場合は、設計に応じて「nullを先にするか」「nullを後にするか」を決めておくと安全です。

5-4. 日付プロパティで新しい順・古い順にソートする

日付プロパティでソートする例を見てみましょう。

C#
class Article
{
public string Title { get; set; } = "";
public DateTime PublishedAt { get; set; }
}

古い順に並び替える場合です。

C#
List<Article> articles = new List<Article>
{
new Article { Title = "記事A", PublishedAt = new DateTime(2025, 1, 10) },
new Article { Title = "記事B", PublishedAt = new DateTime(2024, 12, 1) },
new Article { Title = "記事C", PublishedAt = new DateTime(2025, 3, 5) }
};

articles.Sort((a, b) => a.PublishedAt.CompareTo(b.PublishedAt));

新しい順に並び替える場合です。

C#
articles.Sort((a, b) => b.PublishedAt.CompareTo(a.PublishedAt));

ブログ記事一覧、ニュース一覧、購入履歴などでは、新しい順のソートがよく使われます。

5-5. 複数条件でソートしたい場合の考え方

複数条件でソートしたい場合は、まず第一条件を比較し、同じだった場合だけ第二条件を比較します。

たとえば、年齢順に並べ、年齢が同じ場合は名前順にする場合です。

C#
people.Sort((a, b) =>
{
int ageCompare = a.Age.CompareTo(b.Age);
if (ageCompare != 0)
{
return ageCompare;
}

return string.Compare(a.Name, b.Name, StringComparison.OrdinalIgnoreCase);
});

考え方は次の通りです。

1. 年齢を比較する
2. 年齢が違えば、その結果を返す
3. 年齢が同じなら、名前を比較する

複数条件が増えてコードが長くなる場合は、後述するLINQのOrderByThenByを使うと読みやすくなります。

6. IComparerを使ってソート条件を再利用する方法

6-1. IComparerとは何か

IComparer<T>は、2つのオブジェクトを比較するためのルールを定義するインターフェースです。List.SortにはIComparer<T>を渡せるため、よく使うソート条件をクラスとして分離できます。

ラムダ式は手軽ですが、同じ比較条件を複数箇所で使う場合は、IComparerにしておくと再利用しやすくなります。

たとえば、商品を価格順に並び替える処理をいろいろな場所で使う場合、毎回ラムダ式を書くよりも、比較用クラスを作る方が管理しやすいです。

6-2. IComparerを実装して独自ソートする

まず、商品クラスを用意します。

C#
class Product
{
public string Name { get; set; } = "";
public int Price { get; set; }
}

次に、価格の安い順に並び替えるIComparerを作ります。

C#
class ProductPriceComparer : IComparer<Product>
{
public int Compare(Product? x, Product? y)
{
if (x == null && y == null) return 0;
if (x == null) return -1;
if (y == null) return 1;

return x.Price.CompareTo(y.Price);
}
}

Compareメソッドでは、xyを比較して、どちらを先に並べるかを決めます。

6-3. SortにIComparerを渡すサンプルコード

作成したIComparerは、Sortに渡して使います。

C#
List<Product> products = new List<Product>
{
new Product { Name = "Keyboard", Price = 5000 },
new Product { Name = "Mouse", Price = 2000 },
new Product { Name = "Monitor", Price = 30000 }
};

products.Sort(new ProductPriceComparer());

foreach (var product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}

出力結果です。

Mouse: 2000円
Keyboard: 5000円
Monitor: 30000円

このように、ソート条件をクラスとして切り出すことで、同じ並び替えルールを何度でも使えます。

6-4. ラムダ式とIComparerの使い分け

ラムダ式とIComparerは、次のように使い分けるとよいでしょう。

一度しか使わない簡単なソートなら、ラムダ式が便利です。

C#
products.Sort((a, b) => a.Price.CompareTo(b.Price));

複数箇所で使うソートや、比較条件が複雑なソートなら、IComparerが向いています。

C#
products.Sort(new ProductPriceComparer());

実務では、単純な条件はラムダ式、再利用したい条件はIComparerという使い分けがよく使われます。

7. SortとLINQのOrderByの違い

7-1. Sortは元のListを変更する

Sortは元のListを直接並び替えます。

C#
List<int> numbers = new List<int> { 3, 1, 2 };

numbers.Sort();

Console.WriteLine(string.Join(", ", numbers));
// 出力: 1, 2, 3

この場合、numbers自体の順序が変わっています。

元の順序を残す必要がない場合や、リストをそのまま並び替えて使いたい場合はSortが便利です。

7-2. OrderByは並び替えた結果を新しく返す

LINQのOrderByは、元のListを変更せず、並び替えた結果を返します。LINQの並び替え操作では、1つ以上の属性を基準にシーケンスの要素を並び替えられます。

C#
List<int> numbers = new List<int> { 3, 1, 2 };

var sortedNumbers = numbers.OrderBy(x => x).ToList();

Console.WriteLine(string.Join(", ", numbers));
// 出力: 3, 1, 2

Console.WriteLine(string.Join(", ", sortedNumbers));
// 出力: 1, 2, 3

numbersは元の順序のままで、sortedNumbersに並び替え後の結果が入ります。

7-3. 昇順はOrderBy、降順はOrderByDescendingを使う

LINQで昇順にする場合はOrderByを使います。

C#
var sorted = numbers.OrderBy(x => x).ToList();

降順にする場合はOrderByDescendingを使います。

C#
var sortedDesc = numbers.OrderByDescending(x => x).ToList();

オブジェクトのプロパティで並び替える場合も同じです。

C#
var ageAsc = people.OrderBy(p => p.Age).ToList();

var ageDesc = people.OrderByDescending(p => p.Age).ToList();

7-4. 複数条件はThenBy・ThenByDescendingを使う

LINQで複数条件のソートをしたい場合は、ThenByThenByDescendingを使います。

C#
var sortedPeople = people
.OrderBy(p => p.Age)
.ThenBy(p => p.Name)
.ToList();

このコードは、年齢の昇順で並び替え、年齢が同じ場合は名前の昇順で並び替えます。

降順を組み合わせることもできます。

C#
var sortedPeople = people
.OrderByDescending(p => p.Age)
.ThenBy(p => p.Name)
.ToList();

LINQの並び替えでは、最初の条件で主な順序を決め、追加の条件で同じグループ内の順序を決められます。

7-5. SortとOrderByはどちらを使うべきか

SortOrderByは、目的によって使い分けます。

元のListを直接並び替えてよい場合は、Sortが向いています。

C#
people.Sort((a, b) => a.Age.CompareTo(b.Age));

元のListを変更したくない場合は、OrderByが向いています。

C#
var sortedPeople = people.OrderBy(p => p.Age).ToList();

また、複数条件のソートはOrderByThenByの方が読みやすくなることが多いです。

C#
var sortedPeople = people
.OrderBy(p => p.Age)
.ThenBy(p => p.Name)
.ToList();

一方で、単純な昇順・降順ならSortでも十分です。

8. List.Sortでよくあるエラーと注意点

8-1. 比較できない型をSortしようとした場合

Sort()を引数なしで使う場合、要素同士を比較できる必要があります。intstringDateTimeのような型は標準で比較できますが、独自クラスでは比較方法がわからないため、エラーになることがあります。

たとえば、次のようなクラスがあるとします。

C#
class User
{
public string Name { get; set; } = "";
}

このまま引数なしでSort()すると、比較方法がないため正しくソートできません。

C#
List<User> users = new List<User>
{
new User { Name = "Taro" },
new User { Name = "Hanako" }
};

// 比較方法がないため問題になる
// users.Sort();

この場合は、ラムダ式で比較条件を指定します。

C#
users.Sort((a, b) => a.Name.CompareTo(b.Name));

8-2. Compareメソッドの戻り値の意味

Sortに渡す比較処理では、戻り値の意味を理解しておくことが重要です。

負の値: aをbより前に置く
0: aとbは同じ順序として扱う
正の値: aをbより後に置く

たとえば、昇順では次のように書きます。

C#
numbers.Sort((a, b) => a.CompareTo(b));

降順では逆にします。

C#
numbers.Sort((a, b) => b.CompareTo(a));

比較処理の戻り値が一貫していないと、ソート結果が不正になったり、例外が発生したりする可能性があります。Sortの比較処理では、比較関数の実装に問題がある場合に例外が発生することがあります。

8-3. ソート結果が想定と違うときの確認ポイント

ソート結果が想定と違う場合は、次の点を確認しましょう。

まず、昇順と降順の比較が逆になっていないか確認します。

C#
// 昇順
numbers.Sort((a, b) => a.CompareTo(b));

// 降順
numbers.Sort((a, b) => b.CompareTo(a));

次に、比較しているプロパティが正しいか確認します。

C#
// 年齢順にしたいのにIdを比較していないか?
people.Sort((a, b) => a.Age.CompareTo(b.Age));

文字列の場合は、大文字・小文字、全角・半角、カルチャの影響も確認しましょう。

C#
names.Sort(StringComparer.OrdinalIgnoreCase);

複数条件の場合は、第一条件が同じときだけ第二条件を比較しているかも大切です。

C#
people.Sort((a, b) =>
{
int result = a.Age.CompareTo(b.Age);
if (result != 0) return result;

return a.Name.CompareTo(b.Name);
});

8-4. 安定ソートが必要な場合の注意点

List.Sortを使うときに注意したいのが、安定ソートではないという点です。安定ソートとは、比較結果が同じ要素について、元の順序を保つソートのことです。

たとえば、同じ年齢のユーザーが複数いる場合、List.Sortでは同じ年齢同士の元の順序が保証されない可能性があります。

元の順序を保ちながら複数条件で並び替えたい場合は、LINQのOrderByThenByの利用を検討するとよいでしょう。

C#
var sortedPeople = people
.OrderBy(p => p.Age)
.ThenBy(p => p.Name)
.ToList();

特に、画面表示や帳票出力などで「同じ条件のデータは元の順番を保ちたい」という要件がある場合は、ソート方法を慎重に選びましょう。

8-5. パフォーマンス面で気をつけること

大量データをソートする場合は、比較処理の中身がパフォーマンスに影響します。

たとえば、比較のたびに重い計算やデータベースアクセスを行うのは避けるべきです。

C#
// 避けたい例: 比較のたびに重い処理を呼ぶ
items.Sort((a, b) => GetScore(a).CompareTo(GetScore(b)));

このような場合は、先に比較に使う値を計算しておく、LINQで一時的にキーを作る、データ取得時点で並び替えるなどの工夫が必要です。

また、元のListを変更してよいならSort、元の順序を残したいならOrderByというように、不要なコピーを作らないこともパフォーマンス面では重要です。

9. List.Sortの実践サンプル集

9-1. intのListを昇順・降順にする

昇順にする例です。

C#
List<int> numbers = new List<int> { 10, 3, 7, 1, 5 };

numbers.Sort();

Console.WriteLine(string.Join(", ", numbers));
// 出力: 1, 3, 5, 7, 10

降順にする例です。

C#
List<int> numbers = new List<int> { 10, 3, 7, 1, 5 };

numbers.Sort((a, b) => b.CompareTo(a));

Console.WriteLine(string.Join(", ", numbers));
// 出力: 10, 7, 5, 3, 1

SortReverseを使う降順の例です。

C#
numbers.Sort();
numbers.Reverse();

9-2. stringのListを五十音順・アルファベット順にする

アルファベット順に並び替える例です。

C#
List<string> names = new List<string> { "Taro", "Hanako", "Akira", "Jiro" };

names.Sort();

Console.WriteLine(string.Join(", ", names));
// 出力例: Akira, Hanako, Jiro, Taro

大文字・小文字を無視する例です。

C#
List<string> words = new List<string> { "banana", "Apple", "cherry", "apple" };

words.Sort(StringComparer.OrdinalIgnoreCase);

Console.WriteLine(string.Join(", ", words));
// 出力例: Apple, apple, banana, cherry

日本語の文字列を並び替える例です。

C#
List<string> items = new List<string> { "りんご", "みかん", "いちご", "ぶどう" };

items.Sort();

foreach (var item in items)
{
Console.WriteLine(item);
}

日本語の厳密な五十音順が必要な場合は、単純なSort()だけでなく、アプリケーションの要件に合った比較方法を検討しましょう。

9-3. オブジェクトのListを価格順に並び替える

商品を価格の安い順に並び替える例です。

C#
class Product
{
public string Name { get; set; } = "";
public int Price { get; set; }
}

List<Product> products = new List<Product>
{
new Product { Name = "ノートPC", Price = 120000 },
new Product { Name = "マウス", Price = 2000 },
new Product { Name = "キーボード", Price = 8000 }
};

products.Sort((a, b) => a.Price.CompareTo(b.Price));

foreach (var product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}

出力結果です。

マウス: 2000円
キーボード: 8000円
ノートPC: 120000円

価格の高い順にする場合です。

C#
products.Sort((a, b) => b.Price.CompareTo(a.Price));

9-4. オブジェクトのListを名前順に並び替える

商品名順に並び替える例です。

C#
products.Sort((a, b) => string.Compare(
a.Name,
b.Name,
StringComparison.OrdinalIgnoreCase
));

foreach (var product in products)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}

ユーザー一覧を名前順にする場合も同じ考え方です。

C#
class User
{
public string Name { get; set; } = "";
public int Age { get; set; }
}

List<User> users = new List<User>
{
new User { Name = "Taro", Age = 30 },
new User { Name = "Hanako", Age = 25 },
new User { Name = "Jiro", Age = 20 }
};

users.Sort((a, b) => string.Compare(
a.Name,
b.Name,
StringComparison.OrdinalIgnoreCase
));

文字列プロパティでソートするときは、nullの可能性や大文字・小文字を区別するかどうかを意識すると、想定外の結果を防ぎやすくなります。

9-5. 複数条件で並び替える

最後に、複数条件で並び替える実践例を見てみましょう。

商品をカテゴリ順に並び替え、同じカテゴリ内では価格の安い順にする例です。

C#
class Item
{
public string Category { get; set; } = "";
public string Name { get; set; } = "";
public int Price { get; set; }
}

List<Item> items = new List<Item>
{
new Item { Category = "PC", Name = "ノートPC", Price = 120000 },
new Item { Category = "Accessory", Name = "マウス", Price = 2000 },
new Item { Category = "Accessory", Name = "キーボード", Price = 8000 },
new Item { Category = "PC", Name = "デスクトップPC", Price = 150000 }
};

items.Sort((a, b) =>
{
int categoryCompare = string.Compare(
a.Category,
b.Category,
StringComparison.OrdinalIgnoreCase
);

if (categoryCompare != 0)
{
return categoryCompare;
}

return a.Price.CompareTo(b.Price);
});

foreach (var item in items)
{
Console.WriteLine($"{item.Category} - {item.Name}: {item.Price}円");
}

出力例です。

Accessory - マウス: 2000円
Accessory - キーボード: 8000円
PC - ノートPC: 120000円
PC - デスクトップPC: 150000円

同じ処理をLINQで書くと、次のようになります。

C#
var sortedItems = items
.OrderBy(x => x.Category)
.ThenBy(x => x.Price)
.ToList();

複数条件がある場合は、Sortでも書けますが、OrderByThenByを使った方が読みやすいケースも多いです。

まとめ

C#でListを並び替えるなら、まず覚えておきたいのがList.Sortです。Sort()を使えば、intstringDateTimeなどの基本的な型を簡単に昇順でソートできます。

降順にしたい場合は、Sort()のあとにReverse()を使う方法や、ラムダ式でb.CompareTo(a)と書く方法があります。特に数値の降順では、b - aのような引き算ではなく、CompareToを使う方が安全です。

オブジェクトのListを並び替える場合は、プロパティを指定して比較します。

C#
people.Sort((a, b) => a.Age.CompareTo(b.Age));

複数条件でソートしたい場合は、比較結果が同じときだけ次の条件を比較します。

C#
people.Sort((a, b) =>
{
int result = a.Age.CompareTo(b.Age);
if (result != 0) return result;

return a.Name.CompareTo(b.Name);
});

同じソート条件を何度も使うならIComparer、元のListを変更したくないならLINQのOrderBy、複数条件を読みやすく書きたいならThenByを使うと便利です。

List.Sortはシンプルですが、昇順・降順・条件指定・オブジェクトのプロパティ指定まで幅広く対応できます。C#でリストの並び替えを行うときは、まずSortの基本を押さえ、必要に応じてラムダ式、IComparer、LINQを使い分けるのがおすすめです。