C# OrderByの使い方を完全解説|昇順・降順・複数条件ソートまでわかる Linq 入門

はじめに

C#で一覧データを扱うとき、「年齢順に並べたい」「価格の安い順に表示したい」「日付が新しい順に並び替えたい」といった場面は非常によくあります。そんなときに便利なのが、LINQで使えるOrderByです。

OrderByを使うと、Listや配列、オブジェクトの一覧を簡単に昇順で並び替えることができます。また、降順にしたい場合はOrderByDescending、複数条件で並び替えたい場合はThenByThenByDescendingを組み合わせます。

この記事では、C#のOrderByの基本から、昇順・降順・複数条件ソート、よくあるエラー、Sortとの違い、応用的な使い方まで、初心者にもわかりやすく解説します。

1. C#のOrderByとは?LINQでデータを並び替える基本

1-1. OrderByでできること

OrderByは、C#でコレクションの要素を指定した条件に従って昇順に並び替えるためのLINQメソッドです。

たとえば、次のようなデータを並び替えられます。

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

var result = numbers.OrderBy(x => x);

foreach (var number in result)
{
Console.WriteLine(number);
}

実行結果は次のようになります。

C#
1
2
3
5
8

OrderByを使うことで、数値、文字列、日付、オブジェクトのプロパティなどを基準にして、簡単にデータを並び替えることができます。

1-2. OrderByとLINQの関係

OrderByはLINQの機能のひとつです。LINQとは、C#で配列やList、データベースなどのデータを統一的に操作するための仕組みです。

LINQには、次のようなメソッドがあります。

C#
Where
Select
OrderBy
OrderByDescending
ThenBy
GroupBy

その中でOrderByは、データの並び替えを担当します。

OrderByを使うには、基本的に次のusingが必要です。

C#
using System.Linq;

最近のC#プロジェクトでは最初から使えることも多いですが、環境によってはusing System.Linq;がないとOrderByが見つからないエラーになります。

1-3. OrderByを使う場面の具体例

OrderByは、実務でもよく使われます。

たとえば、次のような場面です。

C#
ユーザー一覧を年齢順に並べる
商品一覧を価格の安い順に並べる
注文履歴を日付順に並べる
社員一覧を名前順に並べる
ランキングをスコア順に並べる

画面に一覧を表示するときや、集計前にデータを整理したいときに、OrderByは非常に便利です。

1-4. List・配列・オブジェクト一覧で使える理由

OrderByは、IEnumerable<T>に対して使えます。

Listや配列はIEnumerable<T>として扱えるため、OrderByを使って並び替えることができます。

C#
var list = new List<int> { 3, 1, 2 };
var array = new int[] { 3, 1, 2 };

var sortedList = list.OrderBy(x => x);
var sortedArray = array.OrderBy(x => x);

また、クラスの一覧に対しても使えます。

C#
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
C#
var users = new List<User>
{
new User { Name = "Taro", Age = 30 },
new User { Name = "Hanako", Age = 25 },
new User { Name = "Jiro", Age = 20 }
};

var sortedUsers = users.OrderBy(user => user.Age);

このように、OrderByは単純な値だけでなく、オブジェクトのプロパティを基準にした並び替えにも使えます。

2. OrderByの基本的な使い方|昇順ソート

2-1. OrderByの基本構文

OrderByの基本構文は次の通りです。

C#
var result = collection.OrderBy(x => x);

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

C#
var result = collection.OrderBy(x => x.PropertyName);

x => x.PropertyNameの部分はラムダ式です。
「各要素のどの値を基準に並び替えるか」を指定しています。

2-2. 数値を昇順で並び替える例

数値を小さい順に並べる場合は、次のように書きます。

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

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

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}

実行結果は次の通りです。

C#
1
3
5
7
10

数値の昇順ソートでは、最も小さい値から大きい値へ順番に並びます。

2-3. 文字列を昇順で並び替える例

文字列を昇順で並び替えることもできます。

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

var sortedNames = names.OrderBy(name => name);

foreach (var name in sortedNames)
{
Console.WriteLine(name);
}

実行結果は次のようになります。

C#
Akira
Hanako
Jiro
Taro

文字列の場合は、通常は文字コードやカルチャに基づいて並び替えられます。英字の場合はアルファベット順に近い形になります。

2-4. オブジェクトのプロパティで昇順ソートする例

実務では、単純な数値や文字列だけでなく、オブジェクトの一覧を並び替えることが多いです。

C#
public class Product
{
public string Name { get; set; }
public int Price { get; set; }
}
C#
var products = new List<Product>
{
new Product { Name = "Keyboard", Price = 3000 },
new Product { Name = "Mouse", Price = 1500 },
new Product { Name = "Monitor", Price = 20000 }
};

var sortedProducts = products.OrderBy(product => product.Price);

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

実行結果は次の通りです。

C#
Mouse: 1500
Keyboard: 3000
Monitor: 20000

product => product.Priceと書くことで、商品の価格を基準に昇順で並び替えています。

2-5. OrderByの戻り値とToListの使い方

OrderByの戻り値は、元のListそのものではありません。
並び替えられた結果を表すIOrderedEnumerable<T>が返されます。

そのため、Listとして使いたい場合はToList()を付けます。

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

配列として取得したい場合はToArray()を使います。

C#
var sortedArray = numbers.OrderBy(x => x).ToArray();

重要なのは、OrderByを呼び出しても元のListの順番は変わらないという点です。

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

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

Console.WriteLine(string.Join(", ", numbers));
Console.WriteLine(string.Join(", ", sortedNumbers));

実行結果は次のようになります。

C#
3, 1, 2
1, 2, 3

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

3. OrderByDescendingの使い方|降順ソート

3-1. OrderByDescendingの基本構文

降順で並び替えたい場合は、OrderByDescendingを使います。

C#
var result = collection.OrderByDescending(x => x);

オブジェクトのプロパティで降順ソートする場合は、次のように書きます。

C#
var result = collection.OrderByDescending(x => x.PropertyName);

OrderByが昇順なのに対して、OrderByDescendingは降順です。

3-2. 数値を降順で並び替える例

数値を大きい順に並べる例です。

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

var sortedNumbers = numbers.OrderByDescending(x => x);

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}

実行結果は次の通りです。

C#
10
7
5
3
1

ランキングや売上順、スコア順などでは、降順ソートを使うことがよくあります。

3-3. 文字列を降順で並び替える例

文字列を逆順に並び替える場合も、OrderByDescendingを使います。

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

var sortedNames = names.OrderByDescending(name => name);

foreach (var name in sortedNames)
{
Console.WriteLine(name);
}

実行結果は次のようになります。

C#
Taro
Jiro
Hanako
Akira

昇順とは逆の順番で並びます。

3-4. オブジェクトのプロパティで降順ソートする例

商品の価格を高い順に並べたい場合は、次のように書きます。

C#
var products = new List<Product>
{
new Product { Name = "Keyboard", Price = 3000 },
new Product { Name = "Mouse", Price = 1500 },
new Product { Name = "Monitor", Price = 20000 }
};

var sortedProducts = products.OrderByDescending(product => product.Price);

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

実行結果は次の通りです。

C#
Monitor: 20000
Keyboard: 3000
Mouse: 1500

高い順、日付の新しい順、スコアの高い順などは、OrderByDescendingを使うと簡単です。

3-5. OrderByとOrderByDescendingの使い分け

OrderByOrderByDescendingは、並び順によって使い分けます。

昇順にしたい場合はOrderByです。

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

降順にしたい場合はOrderByDescendingです。

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

価格の安い順、年齢の若い順、日付の古い順はOrderByを使います。
価格の高い順、年齢の高い順、日付の新しい順はOrderByDescendingを使います。

4. 複数条件でソートする方法|ThenBy・ThenByDescending

4-1. 複数条件ソートが必要になるケース

複数条件ソートとは、最初の条件で並び替えたあと、同じ値の中でさらに別の条件で並び替えることです。

たとえば、社員一覧で次のように並べたい場合があります。

C#
部署名の昇順
同じ部署の中では年齢の昇順

このような場合は、OrderByのあとにThenByを使います。

4-2. ThenByで2つ目の条件を昇順にする

ThenByは、2つ目以降の条件を昇順で指定するときに使います。

C#
public class Employee
{
public string Department { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
C#
var employees = new List<Employee>
{
new Employee { Department = "Sales", Name = "Taro", Age = 30 },
new Employee { Department = "Sales", Name = "Hanako", Age = 25 },
new Employee { Department = "Dev", Name = "Jiro", Age = 28 },
new Employee { Department = "Dev", Name = "Akira", Age = 22 }
};

var sortedEmployees = employees
.OrderBy(e => e.Department)
.ThenBy(e => e.Age);

foreach (var employee in sortedEmployees)
{
Console.WriteLine($"{employee.Department}: {employee.Name}, {employee.Age}");
}

このコードでは、まずDepartmentで昇順に並べ、同じ部署内ではAgeの昇順で並べます。

4-3. ThenByDescendingで2つ目の条件を降順にする

2つ目の条件を降順にしたい場合は、ThenByDescendingを使います。

C#
var sortedEmployees = employees
.OrderBy(e => e.Department)
.ThenByDescending(e => e.Age);

この場合、部署名は昇順ですが、同じ部署内では年齢が高い順に並びます。

最初の条件と2つ目の条件で、昇順・降順を自由に組み合わせることができます。

C#
var result = employees
.OrderByDescending(e => e.Department)
.ThenBy(e => e.Name);

この例では、部署名は降順、同じ部署内では名前を昇順で並び替えます。

4-4. 3つ以上の条件で並び替える方法

3つ以上の条件で並び替える場合も、ThenByThenByDescendingを続けて書きます。

C#
var sortedEmployees = employees
.OrderBy(e => e.Department)
.ThenBy(e => e.Age)
.ThenBy(e => e.Name);

このコードでは、次の順番で並び替えます。

C#
1. Departmentの昇順
2. Ageの昇順
3. Nameの昇順

条件が増えても、最初だけOrderByを使い、その後はThenByを使うのが基本です。

4-5. OrderByを連続で使うと意図通りにならない理由

複数条件ソートで初心者がやりがちなのが、OrderByを連続で使う書き方です。

C#
var sortedEmployees = employees
.OrderBy(e => e.Department)
.OrderBy(e => e.Age);

この書き方では、最初のOrderBy(e => e.Department)の並び替えが、次のOrderBy(e => e.Age)で上書きされるような形になります。

複数条件で並び替えたい場合は、次のように書きます。

C#
var sortedEmployees = employees
.OrderBy(e => e.Department)
.ThenBy(e => e.Age);

最初の条件はOrderBy、2つ目以降の条件はThenByと覚えるとわかりやすいです。

5. 実践例で学ぶC# OrderByの使い方

5-1. 年齢順にユーザー一覧を並び替える

ユーザー一覧を年齢の若い順に並べる例です。

C#
public class User
{
public string Name { get; set; }
public int Age { get; set; }
}
C#
var users = new List<User>
{
new User { Name = "Taro", Age = 30 },
new User { Name = "Hanako", Age = 22 },
new User { Name = "Jiro", Age = 25 }
};

var sortedUsers = users.OrderBy(user => user.Age).ToList();

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

実行結果は次の通りです。

C#
Hanako: 22
Jiro: 25
Taro: 30

年齢の高い順にしたい場合は、OrderByDescendingを使います。

C#
var sortedUsers = users.OrderByDescending(user => user.Age).ToList();

5-2. 名前順に社員一覧を並び替える

社員一覧を名前順に並べる例です。

C#
var employees = new List<Employee>
{
new Employee { Department = "Sales", Name = "Suzuki", Age = 30 },
new Employee { Department = "Dev", Name = "Tanaka", Age = 28 },
new Employee { Department = "HR", Name = "Aoki", Age = 35 }
};

var sortedEmployees = employees.OrderBy(e => e.Name).ToList();

foreach (var employee in sortedEmployees)
{
Console.WriteLine(employee.Name);
}

実行結果は次のようになります。

C#
Aoki
Suzuki
Tanaka

名前やコード、カテゴリ名など、文字列のプロパティを基準に並べるときにもOrderByは便利です。

5-3. 日付順にデータを並び替える

日付順に並び替える場合も、OrderByを使います。

C#
public class Order
{
public int Id { get; set; }
public DateTime OrderedAt { get; set; }
}
C#
var orders = new List<Order>
{
new Order { Id = 1, OrderedAt = new DateTime(2024, 5, 10) },
new Order { Id = 2, OrderedAt = new DateTime(2024, 3, 15) },
new Order { Id = 3, OrderedAt = new DateTime(2024, 7, 1) }
};

var sortedOrders = orders.OrderBy(order => order.OrderedAt).ToList();

foreach (var order in sortedOrders)
{
Console.WriteLine($"{order.Id}: {order.OrderedAt:yyyy/MM/dd}");
}

実行結果は次の通りです。

C#
2: 2024/03/15
1: 2024/05/10
3: 2024/07/01

日付が古い順に並べたい場合はOrderBy、新しい順に並べたい場合はOrderByDescendingを使います。

C#
var latestOrders = orders.OrderByDescending(order => order.OrderedAt).ToList();

5-4. 商品価格を安い順・高い順に並び替える

商品価格を安い順に並べる場合は、OrderByを使います。

C#
var cheapProducts = products.OrderBy(product => product.Price).ToList();

高い順に並べる場合は、OrderByDescendingを使います。

C#
var expensiveProducts = products.OrderByDescending(product => product.Price).ToList();

ECサイトや管理画面では、「価格の安い順」「価格の高い順」のような並び替え機能をよく実装します。

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

ユーザーが選んだ並び順に応じて、OrderByOrderByDescendingを切り替える設計にすると実用的です。

5-5. スコア順にランキングを作成する

ランキングを作る場合は、スコアの高い順に並び替えることが多いため、OrderByDescendingを使います。

C#
public class Player
{
public string Name { get; set; }
public int Score { get; set; }
}
C#
var players = new List<Player>
{
new Player { Name = "Alice", Score = 120 },
new Player { Name = "Bob", Score = 200 },
new Player { Name = "Charlie", Score = 150 }
};

var ranking = players.OrderByDescending(player => player.Score).ToList();

for (int i = 0; i < ranking.Count; i++)
{
Console.WriteLine($"{i + 1}位: {ranking[i].Name} - {ranking[i].Score}点");
}

実行結果は次のようになります。

C#
1: Bob - 200
2: Charlie - 150
3: Alice - 120

スコア、売上、評価点など、大きい値ほど上位にしたい場合はOrderByDescendingが適しています。

5-6. nullを含むデータをOrderByで並び替える

文字列やオブジェクトのプロパティにnullが含まれる場合、並び順や例外に注意が必要です。

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

var sortedNames = names.OrderBy(name => name).ToList();

foreach (var name in sortedNames)
{
Console.WriteLine(name ?? "(null)");
}

この場合、nullは先頭側に並ぶことがあります。

nullを最後に並べたい場合は、次のように書けます。

C#
var sortedNames = names
.OrderBy(name => name == null)
.ThenBy(name => name)
.ToList();

name == nullは、nullならtrue、そうでなければfalseになります。
falseの方が先に並ぶため、nullではない値が先、nullが後ろになります。

オブジェクトのプロパティがnullになる可能性がある場合は、null条件演算子を使うと安全です。

C#
var sortedUsers = users
.OrderBy(user => user.Name ?? "")
.ToList();

6. OrderByでよくあるエラー・つまずきポイント

6-1. using System.Linqがない場合のエラー

OrderByを使おうとして、次のようなエラーが出ることがあります。

C#
'List<int>' does not contain a definition for 'OrderBy'

この場合は、System.Linqが読み込まれていない可能性があります。

ファイルの先頭に次のusingを追加します。

C#
using System.Linq;

LINQの拡張メソッドを使うためには、この名前空間が必要です。

6-2. OrderByしたのに元のListが変わらない理由

OrderByを使っても、元のListの順番は変わりません。

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

numbers.OrderBy(x => x);

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

実行結果は次のようになります。

C#
3, 1, 2

OrderByは、元のListを直接変更するのではなく、並び替え結果を返します。

正しく使うには、結果を変数に代入します。

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

または、元の変数に再代入します。

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

6-3. ToListを忘れたときの挙動

OrderByの結果は、すぐにListになるわけではありません。

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

この時点のsortedNumbersは、IOrderedEnumerable<int>です。

Listとして扱いたい場合は、ToList()を付けます。

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

特に、並び替え後にAddRemoveなどList特有の操作をしたい場合は、ToList()が必要です。

C#
var sortedNumbers = numbers.OrderBy(x => x).ToList();
sortedNumbers.Add(100);

6-4. OrderByとSortの違いで混乱しやすい点

OrderBySortは、どちらも並び替えに使えますが、動きが違います。

OrderByは、並び替えた結果を返します。

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

一方、List.Sortは元のList自体を並び替えます。

C#
numbers.Sort();

元のListを変更したくない場合はOrderBy、元のListを直接変更してよい場合はSortを使うと考えるとわかりやすいです。

6-5. null参照で例外が発生するケース

オブジェクト自体やプロパティがnullの場合、書き方によっては例外が発生します。

C#
var sortedUsers = users.OrderBy(user => user.Name.Length).ToList();

このコードでNamenullのユーザーがいると、NullReferenceExceptionが発生します。

安全に書くには、次のようにします。

C#
var sortedUsers = users
.OrderBy(user => user.Name == null)
.ThenBy(user => user.Name?.Length ?? 0)
.ToList();

または、単純に文字列として並べるだけなら次のように書けます。

C#
var sortedUsers = users
.OrderBy(user => user.Name ?? "")
.ToList();

nullの可能性があるデータでは、???.を使って安全に並び替えることが大切です。

6-6. 大文字・小文字や日本語文字列の並び順に注意する

文字列をOrderByで並べる場合、大文字・小文字や日本語の並び順が期待と異なることがあります。

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

var sortedWords = words.OrderBy(word => word).ToList();

大文字と小文字を区別せずに並べたい場合は、比較方法を指定することもできます。

C#
var sortedWords = words
.OrderBy(word => word, StringComparer.OrdinalIgnoreCase)
.ToList();

日本語の並び順も、単純な五十音順とは異なる場合があります。
画面表示で自然な並び順が必要な場合は、カルチャや比較ルールを考慮する必要があります。

7. OrderByとSortの違い

7-1. LINQのOrderByは新しい並び順の結果を返す

LINQのOrderByは、元のコレクションを直接変更しません。
並び替えた結果を新しく返します。

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

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

この場合、numbersは元の順番のままです。

C#
Console.WriteLine(string.Join(", ", numbers));

結果は次の通りです。

C#
3, 1, 2

元データを残しつつ、並び替えた結果だけ使いたい場合にOrderByは便利です。

7-2. List.Sortは元のList自体を並び替える

List.Sortは、Listそのものの順番を変更します。

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

numbers.Sort();

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

実行結果は次の通りです。

C#
1, 2, 3

Sortは元のListを直接変更するため、別の変数に結果を受け取る必要はありません。

オブジェクトのプロパティで並び替える場合は、比較処理を書きます。

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

7-3. OrderByを使うべきケース

OrderByは、次のようなケースに向いています。

C#
元のListを変更したくない
LINQでWhereやSelectと組み合わせたい
読みやすいコードを書きたい
複数条件ソートを簡単に書きたい
IEnumerable<T>として処理したい

たとえば、条件で絞り込んでから並び替える場合は、OrderByが自然です。

C#
var result = users
.Where(user => user.Age >= 20)
.OrderBy(user => user.Name)
.ToList();

LINQの流れの中で並び替えたい場合は、OrderByを使うとコードが読みやすくなります。

7-4. Sortを使うべきケース

Sortは、次のようなケースに向いています。

C#
元のList自体を並び替えたい
List<T>を直接操作している
余計なListを作りたくない
単純な並び替えだけをしたい

たとえば、数値Listをその場で並び替えるだけなら、Sortで十分です。

C#
numbers.Sort();

降順にしたい場合は、SortしたあとにReverseする方法もあります。

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

ただし、複数条件の並び替えではOrderByThenByの方が読みやすい場合が多いです。

7-5. 可読性・保守性・パフォーマンスの違い

OrderByはLINQのメソッドチェーンで書けるため、可読性が高いです。

C#
var result = users
.Where(user => user.IsActive)
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();

一方、SortはListを直接変更するため、動作が明確で余計なコレクションを作らないというメリットがあります。

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

保守性を重視するならOrderBy、元のListを直接並び替えたいならSortという使い分けが基本です。

パフォーマンス面では、大量データを扱う場合に差が出ることがあります。
ただし、通常のアプリケーションでは、まず読みやすさを優先し、必要になったらパフォーマンスを測定して最適化するのが現実的です。

8. OrderByをさらに使いこなす応用テクニック

8-1. カスタムComparerを使って独自の並び順にする

OrderByでは、比較方法を指定することができます。

たとえば、大文字・小文字を区別せずに文字列を並べる場合は、StringComparer.OrdinalIgnoreCaseを使います。

C#
var names = new List<string> { "taro", "Hanako", "jiro", "Akira" };

var sortedNames = names
.OrderBy(name => name, StringComparer.OrdinalIgnoreCase)
.ToList();

独自の比較ルールを作りたい場合は、IComparer<T>を実装します。

C#
public class LengthComparer : IComparer<string>
{
public int Compare(string x, string y)
{
return x.Length.CompareTo(y.Length);
}
}
C#
var words = new List<string> { "apple", "dog", "banana", "cat" };

var sortedWords = words
.OrderBy(word => word, new LengthComparer())
.ToList();

この例では、文字列の長さを基準に並び替えています。

8-2. 条件によって昇順・降順を切り替える

画面の並び替えボタンなどでは、昇順と降順を条件によって切り替えたいことがあります。

C#
bool isDescending = true;

var sortedUsers = isDescending
? users.OrderByDescending(user => user.Age).ToList()
: users.OrderBy(user => user.Age).ToList();

このように三項演算子を使うと、条件によってOrderByOrderByDescendingを切り替えられます。

メソッドとしてまとめることもできます。

C#
public List<User> SortUsersByAge(List<User> users, bool descending)
{
return descending
? users.OrderByDescending(user => user.Age).ToList()
: users.OrderBy(user => user.Age).ToList();
}

ユーザーが選んだ並び順に応じて処理を変える場合に便利です。

8-3. ラムダ式で複雑なソート条件を書く

OrderByのキーには、単純なプロパティだけでなく、計算結果や条件式も指定できます。

C#
var sortedUsers = users
.OrderBy(user => user.Age >= 20 ? 0 : 1)
.ThenBy(user => user.Age)
.ToList();

この例では、20歳以上のユーザーを先に並べ、その中で年齢順に並び替えています。

文字列の長さで並び替えることもできます。

C#
var sortedNames = names
.OrderBy(name => name.Length)
.ToList();

ラムダ式を使うことで、柔軟なソート条件を書けます。

8-4. 匿名型を使って複数キーで並び替える

複数のキーをまとめて指定したい場合は、匿名型を使うこともできます。

C#
var sortedUsers = users
.OrderBy(user => new { user.Age, user.Name })
.ToList();

この場合、AgeNameの順に昇順で並び替えます。

ただし、昇順と降順を混在させたい場合は、ThenByThenByDescendingを使う方がわかりやすいです。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenByDescending(user => user.Name)
.ToList();

匿名型はシンプルな複数キー昇順ソートに向いています。

8-5. GroupByとOrderByを組み合わせる

GroupByOrderByを組み合わせると、グループ化した結果を並び替えることができます。

C#
var groupedUsers = users
.GroupBy(user => user.Age)
.OrderBy(group => group.Key);

このコードでは、年齢ごとにグループ化し、年齢の昇順でグループを並べています。

グループ内の要素も並び替えたい場合は、次のように書けます。

C#
var groupedUsers = users
.GroupBy(user => user.Age)
.OrderBy(group => group.Key)
.Select(group => new
{
Age = group.Key,
Users = group.OrderBy(user => user.Name).ToList()
})
.ToList();

この例では、年齢ごとのグループを年齢順に並べ、各グループ内では名前順に並び替えています。

8-6. WhereやSelectとOrderByを組み合わせる

LINQでは、WhereOrderBySelectを組み合わせて使うことがよくあります。

C#
var result = users
.Where(user => user.Age >= 20)
.OrderBy(user => user.Name)
.Select(user => user.Name)
.ToList();

このコードでは、次の順番で処理しています。

C#
1. 20歳以上のユーザーに絞り込む
2. 名前順に並び替える
3. 名前だけを取り出す
4. Listに変換する

LINQはメソッドチェーンで処理の流れを書けるため、慣れると非常に読みやすくなります。

9. OrderByのパフォーマンスと注意点

9-1. OrderByは遅延実行される

OrderByは、呼び出した瞬間にすぐ並び替えが実行されるとは限りません。
LINQには遅延実行という仕組みがあります。

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

この時点では、まだ実際の列挙が行われていない場合があります。

実際に処理が実行されるのは、foreachで列挙したときや、ToList()ToArray()を呼び出したときです。

C#
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}

このタイミングで並び替え結果が使われます。

9-2. ToListやToArrayで実行タイミングが決まる

ToList()ToArray()を呼び出すと、その時点でLINQの処理が実行されます。

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

このコードでは、ToList()を呼び出した時点で並び替えが実行され、結果がListとして保存されます。

何度も同じ並び替え結果を使う場合は、ToList()で一度確定させた方が扱いやすいです。

C#
var sortedUsers = users.OrderBy(user => user.Name).ToList();

Console.WriteLine(sortedUsers.Count);
Console.WriteLine(sortedUsers.First().Name);

遅延実行のまま何度も列挙すると、処理が繰り返される場合があるため注意しましょう。

9-3. 大量データを並び替えるときの注意点

大量データをOrderByで並び替える場合、処理時間やメモリ使用量に注意が必要です。

並び替えは、単純なWhereによる絞り込みよりも負荷が高くなりやすい処理です。

大量データを扱う場合は、次のような工夫が有効です。

C#
必要なデータだけに絞り込んでから並び替える
不要なOrderByを何度も実行しない
ToListのタイミングを意識する
データベース側で並び替えられる場合はDBに任せる

たとえば、先に絞り込んでから並び替えると、ソート対象を減らせます。

C#
var result = users
.Where(user => user.IsActive)
.OrderBy(user => user.Name)
.ToList();

9-4. データベースへのLINQクエリで使う場合の注意点

Entity Frameworkなどでデータベースに対してLINQを使う場合、OrderByはSQLのORDER BYに変換されることがあります。

C#
var users = dbContext.Users
.Where(user => user.IsActive)
.OrderBy(user => user.Name)
.ToList();

この場合、データベース側で並び替えが行われます。

ただし、C#側でしか実行できない複雑な処理をOrderByに書くと、SQLに変換できずエラーになることがあります。

C#
var users = dbContext.Users
.OrderBy(user => SomeCSharpMethod(user.Name))
.ToList();

データベースに対するLINQでは、SQLに変換できるシンプルな式を使うのが基本です。

9-5. 不要なOrderByを避ける書き方

OrderByは便利ですが、必要のない場所で何度も使うと無駄な処理になります。

たとえば、次のようなコードは並び替えが重複しています。

C#
var result = users
.OrderBy(user => user.Name)
.Where(user => user.IsActive)
.OrderBy(user => user.Age)
.ToList();

この場合、最初のOrderBy(user => user.Name)は後のOrderBy(user => user.Age)で意味が薄くなります。

意図が複数条件ソートなら、次のように書きます。

C#
var result = users
.Where(user => user.IsActive)
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();

絞り込み、並び替え、変換の順番を意識すると、読みやすく無駄の少ないコードになります。

10. C# OrderByのよくある質問

10-1. OrderByで降順にするには?

OrderByではなく、OrderByDescendingを使います。

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

オブジェクトのプロパティで降順にする場合は、次のように書きます。

C#
var result = users.OrderByDescending(user => user.Age).ToList();

スコアの高い順、日付の新しい順、価格の高い順などに使います。

10-2. OrderByで複数条件を指定するには?

最初の条件にOrderByを使い、2つ目以降の条件にThenByを使います。

C#
var result = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();

2つ目の条件を降順にしたい場合は、ThenByDescendingを使います。

C#
var result = users
.OrderBy(user => user.Age)
.ThenByDescending(user => user.Name)
.ToList();

10-3. OrderByとThenByの違いは?

OrderByは最初の並び替え条件を指定するメソッドです。
ThenByは、OrderByで並び替えたあと、同じ値の中でさらに並び替えるためのメソッドです。

C#
var result = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();

この例では、まず年齢順に並び、同じ年齢の中では名前順に並びます。

複数条件ソートでは、最初がOrderBy、次からThenByです。

10-4. OrderByとSortはどちらを使うべき?

元のListを変更したくない場合はOrderByを使います。

C#
var sortedUsers = users.OrderBy(user => user.Age).ToList();

元のList自体を並び替えてよい場合はSortを使えます。

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

LINQの流れで処理したい場合や、複数条件ソートを読みやすく書きたい場合はOrderByがおすすめです。

10-5. OrderByで元のListを直接並び替えられる?

OrderByだけでは元のListは直接並び替えられません。
並び替え結果を元の変数に再代入する必要があります。

C#
users = users.OrderBy(user => user.Age).ToList();

元のList自体を直接並び替えたい場合は、List.Sortを使います。

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

OrderByは新しい並び順の結果を返す、Sortは元のListを変更する、と覚えておきましょう。

10-6. OrderByでnullを最後に並べるには?

nullを最後にしたい場合は、まずnullかどうかで並び替え、その後に実際の値で並び替えます。

C#
var sortedNames = names
.OrderBy(name => name == null)
.ThenBy(name => name)
.ToList();

オブジェクトのプロパティがnullの場合も同じ考え方です。

C#
var sortedUsers = users
.OrderBy(user => user.Name == null)
.ThenBy(user => user.Name)
.ToList();

name == nullfalseのデータが先に並び、trueのデータが後に並ぶため、nullを最後にできます。

まとめ

C#のOrderByは、LINQを使ってデータを昇順に並び替えるための基本的なメソッドです。

数値を小さい順に並べる、文字列を名前順に並べる、オブジェクトのプロパティを基準に並べるなど、さまざまな場面で使えます。

昇順にしたい場合はOrderBy、降順にしたい場合はOrderByDescendingを使います。

C#
var asc = numbers.OrderBy(x => x).ToList();
var desc = numbers.OrderByDescending(x => x).ToList();

複数条件で並び替えたい場合は、最初の条件にOrderByを使い、2つ目以降の条件にThenByThenByDescendingを使います。

C#
var result = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();

また、OrderByは元のListを直接変更しない点にも注意が必要です。
並び替え結果をListとして使いたい場合は、ToList()を付けます。

C#
var sortedUsers = users.OrderBy(user => user.Age).ToList();

元のList自体を変更したい場合は、List.Sortを使います。

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

C#で一覧データを扱うなら、OrderByは必ず覚えておきたいLINQの基本機能です。
昇順、降順、複数条件ソート、null対応、Sortとの違いを理解しておくと、実務でも読みやすく保守しやすいコードを書けるようになります。