【C#】LINQでデータを並べ替える:OrderByとThenByによる複数条件ソート

目次

データの並べ替え(ソート)

配列やリストなどのデータを扱う際、「数値を小さい順に並べる」「日付の新しい順に表示する」といった並べ替え(ソート)は、最も基本的かつ重要な操作の一つです。

C#のLINQ(Language Integrated Query)を使用すると、SQLのクエリのように直感的で可読性の高いコードで、複雑なソート処理を記述できます。特に、Excelの並べ替え機能のように「Aの項目で並べ替え、同じならBの項目で並べ替える」といった複数条件の指定も、メソッドチェーン(連鎖)を使って簡単に実現できます。

この記事では、LINQを使用した昇順・降順の並べ替えと、複数キーを使用した高度なソート方法について解説します。


1. 基本的なソート:昇順と降順

LINQでのソートは、元のコレクションを変更せず、並べ替えられた新しいシーケンスを返します(非破壊的操作)。

  • OrderBy(keySelector): 昇順(小さい順、A→Z)に並べ替えます。
  • OrderByDescending(keySelector): 降順(大きい順、Z→A)に並べ替えます。

コード例:映画リストのソート

映画のタイトル、公開年、評価スコアを持つリストを題材に、基本的なソートを行います。

using System;
using System.Collections.Generic;
using System.Linq;

// 映画データを表すクラス
public class Movie
{
    public string Title { get; set; }
    public int ReleaseYear { get; set; }
    public double Rating { get; set; }
}

public class BasicSortExample
{
    public static void Main()
    {
        var movies = new List<Movie>
        {
            new Movie { Title = "The Sci-Fi Epic", ReleaseYear = 2010, Rating = 8.5 },
            new Movie { Title = "Action Hero", ReleaseYear = 2022, Rating = 6.2 },
            new Movie { Title = "Classic Drama", ReleaseYear = 1995, Rating = 9.0 },
            new Movie { Title = "Mystery Case", ReleaseYear = 2010, Rating = 7.8 },
            new Movie { Title = "Comedy Night", ReleaseYear = 2018, Rating = 5.5 }
        };

        // 1. OrderBy: 公開年で昇順(古い順)にソート
        var sortedByYear = movies.OrderBy(m => m.ReleaseYear);

        Console.WriteLine("--- 公開年順 (昇順) ---");
        foreach (var m in sortedByYear)
        {
            Console.WriteLine($"{m.ReleaseYear}: {m.Title}");
        }

        // 2. OrderByDescending: 評価スコアで降順(高い順)にソート
        var sortedByRating = movies.OrderByDescending(m => m.Rating);

        Console.WriteLine("\n--- 評価スコア順 (降順) ---");
        foreach (var m in sortedByRating)
        {
            Console.WriteLine($"Rating {m.Rating}: {m.Title}");
        }
    }
}

出力結果:

--- 公開年順 (昇順) ---
1995: Classic Drama
2010: The Sci-Fi Epic
2010: Mystery Case
2018: Comedy Night
2022: Action Hero

--- 評価スコア順 (降順) ---
Rating 9: Classic Drama
Rating 8.5: The Sci-Fi Epic
Rating 7.8: Mystery Case
Rating 6.2: Action Hero
Rating 5.5: Comedy Night

2. 複数条件でのソート:ThenBy の活用

上記の例で、公開年が同じ「2010年」の映画が2つありました。OrderByだけを使用した場合、これら2つの並び順は不定(または元の順序維持)となります。

「まず公開年で並べ替え、同じ年ならタイトル順に並べ替える」といった第2、第3の条件を指定するには、ThenBy または ThenByDescending メソッドを使用します。

  • ThenBy(keySelector): 直前のソート結果に対して、指定したキーで昇順に再ソートします。
  • ThenByDescending(keySelector): 直前のソート結果に対して、指定したキーで降順に再ソートします。

注意点:

2つ目以降の条件には必ず ThenBy 系を使用してください。再度 OrderBy を使ってしまうと、前のソート結果がリセットされ、最後の条件だけで並べ替えられてしまいます。

コード例:複数キーによるソート

using System;
using System.Collections.Generic;
using System.Linq;

public class MultiKeySortExample
{
    public static void Main()
    {
        var movies = new List<Movie>
        {
            new Movie { Title = "Space Wars", ReleaseYear = 2010, Rating = 7.5 },
            new Movie { Title = "Alien Encounter", ReleaseYear = 2010, Rating = 8.2 },
            new Movie { Title = "Zombie City", ReleaseYear = 2010, Rating = 6.0 },
            new Movie { Title = "Future World", ReleaseYear = 2021, Rating = 7.0 },
            new Movie { Title = "Past Memories", ReleaseYear = 1990, Rating = 9.1 }
        };

        // 複合ソートのロジック:
        // 1. まず「公開年」で昇順 (古い順) に並べる
        // 2. 同じ年の場合は、「評価スコア」で降順 (高い順) に並べる
        // 3. さらにスコアも同じなら、「タイトル」で昇順 (A-Z) に並べる
        
        var complexSort = movies
            .OrderBy(m => m.ReleaseYear)              // 第1キー
            .ThenByDescending(m => m.Rating)          // 第2キー
            .ThenBy(m => m.Title);                    // 第3キー

        Console.WriteLine("--- 年(昇) -> 評価(降) -> タイトル(昇) ---");
        foreach (var m in complexSort)
        {
            Console.WriteLine($"{m.ReleaseYear} | Rate:{m.Rating} | {m.Title}");
        }
    }
}

出力結果:

--- 年(昇) -> 評価(降) -> タイトル(昇) ---
1990 | Rate:9.1 | Past Memories
2010 | Rate:8.2 | Alien Encounter
2010 | Rate:7.5 | Space Wars
2010 | Rate:6 | Zombie City
2021 | Rate:7 | Future World

2010年の映画が3本ありますが、指定通り「評価の高い順(8.2 -> 7.5 -> 6)」に並んでいることが確認できます。


List<T>.Sort() との違い

List<T>クラスには、インスタンスメソッドとしての Sort() も存在します。LINQの OrderBy とは以下の点で異なります。

特徴LINQ (OrderBy)Listメソッド (Sort)
破壊的変更なし (新しいシーケンスを返す)あり (元のリストを書き換える)
戻り値IOrderedEnumerable<T>void
複数条件ThenBy でチェーン可能Comparison<T> でロジックを記述する必要あり
対象配列、List、その他コレクションList<T> のみ

元のデータを保持したままソートしたい場合や、複数条件を簡潔に書きたい場合は、LINQの OrderBy が適しています。


まとめ

LINQを使用することで、データの並べ替えを非常に柔軟に行うことができます。

  • OrderBy / OrderByDescending: 最初のソート条件を指定します。
  • ThenBy / ThenByDescending: 2つ目以降のソート条件を指定します。必ず OrderBy の後に繋げて使用します。

これらを組み合わせることで、SQLの ORDER BY Year ASC, Rating DESC と同様の複雑な並べ替えロジックを、C#のコード上で型安全かつ直感的に記述できます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次