はじめに:「並び替えキー複数」は“人間の並び順ルールをそのままコードにする”技
業務でデータを並び替えるとき、単純に「ID順」だけで済むことはあまりありません。
部署コード昇順、その中で社員区分昇順、さらに名前昇順。
日付の新しい順、その中でステータス順、その中で登録者名順。
こういう「複数のキーで並び替える」ルールを、きれいに・安全に書けるのが LINQ の並び替え機能です。
ここでは、初心者向けに
単一キーの OrderBy のおさらい
ThenBy / ThenByDescending による複数キー並び替え
業務でよくある「優先順位付きソート」の書き方
ユーティリティ化して読みやすくするコツ
を、例題付きでかみ砕いて説明します。
基本のおさらい:OrderBy と OrderByDescending
単一キーでの並び替え
まずは一番基本の形から確認します。
public class Employee
{
public string Department { get; set; } = "";
public string Name { get; set; } = "";
public int Age { get; set; }
}
var employees = new[]
{
new Employee { Department = "A", Name = "Tanaka", Age = 30 },
new Employee { Department = "B", Name = "Sato", Age = 25 },
new Employee { Department = "A", Name = "Suzuki", Age = 28 },
};
C#部署コード昇順で並び替えるなら、こう書きます。
var ordered = employees
.OrderBy(x => x.Department)
.ToList();
C#年齢の降順なら、こうです。
var ordered = employees
.OrderByDescending(x => x.Age)
.ToList();
C#ここまではシンプルな「単一キーのソート」です。
この上に「複数キー」を積み上げていきます。
複数キー並び替えの基本:ThenBy / ThenByDescending
「まずこれで並べて、その中でさらにこれで並べる」
複数キー並び替えの基本形は、次のようなチェーンです。
var ordered = employees
.OrderBy(x => x.Department) // 第1キー
.ThenBy(x => x.Age) // 第2キー
.ThenBy(x => x.Name) // 第3キー
.ToList();
C#意味としては、「まず Department 昇順で並べ、その中で Age 昇順、その中で Name 昇順」です。
人間が自然に考える「ソートの優先順位」を、そのまま左から右に書いていくイメージです。
降順を混ぜたいときは、ThenByDescending を使います。
var ordered = employees
.OrderBy(x => x.Department) // 部署昇順
.ThenByDescending(x => x.Age) // 同じ部署内では年齢降順
.ToList();
C#ここでの重要ポイントは、「最初は必ず OrderBy / OrderByDescending、その後は ThenBy / ThenByDescending」という形になることです。
いきなり ThenBy からは始められません。
業務でよくあるパターン 1:ステータス優先+日付順
「ステータスの優先順位」をコードに落とし込む
例えば、チケット一覧を表示するときに、こういうルールがあるとします。
未対応を一番上に、その次に対応中、一番下に完了。
同じステータスの中では、受付日が新しい順。
モデルを簡単に定義します。
public class Ticket
{
public string Status { get; set; } = ""; // "New", "InProgress", "Done"
public DateTime CreatedAt { get; set; }
}
C#ここで大事なのは、「Status は文字列だが、並び順は文字列順ではない」ということです。
「業務上の優先順位」を数値にマッピングしてあげると、きれいに書けます。
int GetStatusOrder(string status) => status switch
{
"New" => 0,
"InProgress" => 1,
"Done" => 2,
_ => 99
};
C#これを使って並び替えます。
var ordered = tickets
.OrderBy(x => GetStatusOrder(x.Status)) // ステータス優先順位
.ThenByDescending(x => x.CreatedAt) // 同じステータス内では新しい順
.ToList();
C#ここでの重要ポイントは、「業務ルールを“数値の優先順位”に変換してから OrderBy する」というパターンです。
複雑な if 文でソート順を頑張るより、ずっと読みやすくなります。
業務でよくあるパターン 2:NULL や空文字を最後に回す
「値がないものは一番下にしたい」
例えば、「終了日で並び替えたいが、終了日が未設定のものは一番下にしたい」というケース。
public class Task
{
public string Name { get; set; } = "";
public DateTime? EndDate { get; set; } // null の場合は未設定
}
C#単純に OrderBy(x => x.EndDate) とすると、null が先頭に来てしまいます。
「null を最後にしたい」場合は、並び替えキーを工夫します。
var ordered = tasks
.OrderBy(x => x.EndDate == null ? 1 : 0) // null なら 1、値ありなら 0
.ThenBy(x => x.EndDate) // 値あり同士は日付昇順
.ToList();
C#最初の OrderBy で「値ありを先に、null を後ろに」分け、
ThenBy で「値あり同士の中で日付順」にしています。
ここでの重要ポイントは、「複数キーを使うことで、“null を最後に”のような細かい並び順も素直に表現できる」ということです。
1 つのキーで頑張ろうとしないのがコツです。
ユーティリティ化して読みやすくする
並び替えルールをメソッドに閉じ込める
複数キーの並び替えは、慣れていないと少し読みにくく感じることがあります。
業務で何度も使う並び順なら、「並び替え専用メソッド」にしてしまうとコードがすっきりします。
例えば、社員一覧の標準並び順を「部署昇順→職位降順→名前昇順」と決めるとします。
public static class EmployeeOrdering
{
public static IOrderedEnumerable<Employee> OrderByDefault(
this IEnumerable<Employee> source)
{
return source
.OrderBy(x => x.Department)
.ThenByDescending(x => x.PositionRank) // 職位を数値で持っている想定
.ThenBy(x => x.Name);
}
}
C#使う側はこう書けます。
var ordered = employees
.OrderByDefault()
.ToList();
C#ここでの重要ポイントは、「並び順に名前をつける」ことです。OrderByDefault や OrderByDisplayRule のような名前にしておくと、「どの画面も同じルールで並んでいる」ことが一目で分かります。
まとめ:「並び替えキー複数」は“業務の並び順をそのままコードに落とす”ための基本スキル
複数キー並び替えの本質は、
人間が「こう並んでいてほしい」と考える優先順位を、OrderBy と ThenBy のチェーンとして素直に書くこと
です。
押さえておきたいポイントを整理すると、次の通りです。
最初は必ず OrderBy / OrderByDescending、その後に ThenBy / ThenByDescending をつなげる。
業務ルールの優先順位は、数値やフラグにマッピングしてからキーにすると分かりやすい。
null や空文字を最後に回したいときは、「null かどうか」を第1キーにしてから本来のキーで並べる。
よく使う並び順は拡張メソッドなどにまとめて「名前付きの並び順」にすると、チームで共有しやすい。
ここまで腹落ちしていれば、「とりあえず OrderBy 1 個だけ」で済ませる段階から抜けて、
“業務の並び順ルールをそのままコードにできる C# エンジニア”に一歩近づけます。
