C# Tips | コレクション・LINQ:並び替えキー複数

C# C#
スポンサーリンク

はじめに:「並び替えキー複数」は“人間の並び順ルールをそのままコードにする”技

業務でデータを並び替えるとき、単純に「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#

ここでの重要ポイントは、「並び順に名前をつける」ことです。
OrderByDefaultOrderByDisplayRule のような名前にしておくと、「どの画面も同じルールで並んでいる」ことが一目で分かります。


まとめ:「並び替えキー複数」は“業務の並び順をそのままコードに落とす”ための基本スキル

複数キー並び替えの本質は、

人間が「こう並んでいてほしい」と考える優先順位を、
OrderByThenBy のチェーンとして素直に書くこと

です。

押さえておきたいポイントを整理すると、次の通りです。

最初は必ず OrderBy / OrderByDescending、その後に ThenBy / ThenByDescending をつなげる。
業務ルールの優先順位は、数値やフラグにマッピングしてからキーにすると分かりやすい。
null や空文字を最後に回したいときは、「null かどうか」を第1キーにしてから本来のキーで並べる。
よく使う並び順は拡張メソッドなどにまとめて「名前付きの並び順」にすると、チームで共有しやすい。

ここまで腹落ちしていれば、「とりあえず OrderBy 1 個だけ」で済ませる段階から抜けて、
“業務の並び順ルールをそのままコードにできる C# エンジニア”に一歩近づけます。

タイトルとURLをコピーしました