データの並べ替え(ソート)
配列やリストなどのデータを扱う際、「数値を小さい順に並べる」「日付の新しい順に表示する」といった並べ替え(ソート)は、最も基本的かつ重要な操作の一つです。
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#のコード上で型安全かつ直感的に記述できます。
