はじめに:「ソート」は“人間が読みやすい順番に並べ替える作業”
業務システムでは、一覧画面・帳票・CSV 出力など、
「同じデータでも、どの順番で並んでいるか」がものすごく大事になります。
社員一覧なら「社員番号順」
売上一覧なら「日付の昇順」
エラー一覧なら「重要度の高い順」
こういった「並び順」をコードで表現するのが、ソート(並べ替え)です。
C# では、
配列や List に対する「破壊的ソート(中身を書き換える)」と、
LINQ による「新しい並び順の列を作るソート」
の2つの考え方があります。
ここでは初心者向けに、まず LINQ のソートから入り、
そのあと List の Sort、複数キーでのソートまで、かみ砕いて説明していきます。
基本:LINQ の OrderBy / OrderByDescending でソートする
数値や文字列を昇順・降順に並べる
一番シンプルな例からいきます。
using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 5, 2, 9, 1, 3 };
var asc = numbers.OrderBy(x => x); // 昇順
var desc = numbers.OrderByDescending(x => x); // 降順
Console.WriteLine("昇順:");
foreach (var n in asc)
{
Console.WriteLine(n); // 1, 2, 3, 5, 9
}
Console.WriteLine("降順:");
foreach (var n in desc)
{
Console.WriteLine(n); // 9, 5, 3, 2, 1
}
C#ここでの重要ポイントは、「OrderBy は“元の List を書き換えない”」ということです。numbers 自体の順番は変わらず、OrderBy の結果として“並び替えられた列”が新しく返ってきます。
文字列も同じように並べ替えられる
var names = new List<string> { "Charlie", "Alice", "Bob" };
var sorted = names.OrderBy(x => x);
foreach (var n in sorted)
{
Console.WriteLine(n); // Alice, Bob, Charlie
}
C#OrderBy(x => x) の「x => x」は、
「要素そのものをキーとして使う」という意味です。
「何を基準に並べるか」をこの部分で指定します。
オブジェクトを「特定のプロパティ」でソートする
社員を「社員番号順」「名前順」で並べる
業務では、単純な int や string ではなく、
クラスのリストをソートすることがほとんどです。
例えば、こんなクラスがあるとします。
public class Employee
{
public int No { get; set; } // 社員番号
public string Name { get; set; } = "";
}
C#社員のリストを作ります。
var employees = new List<Employee>
{
new Employee { No = 3, Name = "Tanaka" },
new Employee { No = 1, Name = "Sato" },
new Employee { No = 2, Name = "Suzuki" },
};
C#社員番号順に並べたいときは、こう書きます。
var byNo = employees.OrderBy(e => e.No);
foreach (var e in byNo)
{
Console.WriteLine($"{e.No}: {e.Name}");
// 1: Sato
// 2: Suzuki
// 3: Tanaka
}
C#名前の昇順なら、こうです。
var byName = employees.OrderBy(e => e.Name);
C#ここでの重要ポイントは、「OrderBy の中で“ソートキー”を選ぶ」という感覚です。e => e.No なら「社員番号で並べる」、e => e.Name なら「名前で並べる」という意味になります。
複数キーでソートする:ThenBy / ThenByDescending
まず部署、次に社員番号、のような並び順
業務では、「部署コード順 → 部署内では社員番号順」のように、
複数の条件でソートしたいことがよくあります。
例えば、こんなクラスを考えます。
public class Employee
{
public string Department { get; set; } = ""; // 部署コード
public int No { get; set; } // 社員番号
public string Name { get; set; } = "";
}
C#データを用意します。
var employees = new List<Employee>
{
new Employee { Department = "B", No = 3, Name = "Tanaka" },
new Employee { Department = "A", No = 2, Name = "Suzuki" },
new Employee { Department = "A", No = 1, Name = "Sato" },
new Employee { Department = "B", No = 1, Name = "Yamada" },
};
C#「部署コードの昇順 → 同じ部署内では社員番号の昇順」で並べたいときは、OrderBy と ThenBy を組み合わせます。
var sorted = employees
.OrderBy(e => e.Department) // まず部署でソート
.ThenBy(e => e.No); // 次に社員番号でソート
foreach (var e in sorted)
{
Console.WriteLine($"{e.Department}-{e.No}: {e.Name}");
// A-1: Sato
// A-2: Suzuki
// B-1: Yamada
// B-3: Tanaka
}
C#ここでの重要ポイントは、「ソートの優先順位は、OrderBy → ThenBy の順に決まる」ということです。OrderBy が“第一キー”、ThenBy が“第二キー”、さらに ThenBy を重ねれば第三キー…と続けられます。
降順を混ぜたいときは、OrderByDescending や ThenByDescending を使います。
var sorted = employees
.OrderBy(e => e.Department)
.ThenByDescending(e => e.No); // 部署内では社員番号の降順
C#List<T>.Sort と LINQ のソートの違い
List.Sort は「その List 自体を書き換える」
LINQ の OrderBy は「新しい並び順の列を返す」ものでしたが、List<T> には「自分自身を並べ替える」Sort メソッドもあります。
var numbers = new List<int> { 5, 2, 9, 1, 3 };
numbers.Sort(); // numbers 自体が昇順に並び替えられる
foreach (var n in numbers)
{
Console.WriteLine(n); // 1, 2, 3, 5, 9
}
C#ここでの重要ポイントは、「Sort は破壊的(in-place)である」ということです。
元の順番が必要な場合は、Sort を使う前に ToList() などでコピーを作る必要があります。
オブジェクトを Sort するには「比較ルール」が必要
List<T>.Sort でオブジェクトを並べ替える場合、Comparison<T> や IComparer<T> を渡して「どう比べるか」を教えてあげます。
社員番号順に並べる例です。
var employees = new List<Employee>
{
new Employee { No = 3, Name = "Tanaka" },
new Employee { No = 1, Name = "Sato" },
new Employee { No = 2, Name = "Suzuki" },
};
employees.Sort((x, y) => x.No.CompareTo(y.No));
foreach (var e in employees)
{
Console.WriteLine($"{e.No}: {e.Name}");
}
C#(x, y) => x.No.CompareTo(y.No) は、
「x のほうが小さければ負の値、同じなら 0、大きければ正の値を返す」比較関数です。
実務では、
「元の List をそのまま並べ替えたいときは Sort」
「元の List はそのままにしておきたいときは LINQ の OrderBy」
という使い分けをすると分かりやすいです。
実務で意識してほしいポイント
「何順か」をコードにハッキリ書く
業務コードで一番もったいないのは、
「なんとなくソートしているけど、何順なのかが読み取れない」状態です。
OrderBy(e => e.No) なら「社員番号順」OrderBy(e => e.Department).ThenBy(e => e.No) なら「部署→社員番号順」
というように、「何を基準に並べているか」がコードから一目で分かるように書くことが大事です。
ソートは「画面用」「集計用」など用途ごとに分ける
同じデータでも、
画面では「名前順」、CSV では「ID 順」、集計では「日付順」
といったように、用途によって並び順が変わります。
そのときは、
画面用のソートロジック
CSV 用のソートロジック
のように、メソッドや拡張メソッドとして分けておくと、
「どこでどんな順番にしているか」が追いやすくなります。
まとめ:「ソートユーティリティ」は“データに意味のある順番を与える道具”
ソートの本質は、
「ただの集合に、“人間にとって意味のある順番”を与えること」です。
C# / LINQ では、
OrderBy / OrderByDescending で昇順・降順の並び替えができるThenBy / ThenByDescending で複数キーのソートが書けるList<T>.Sort は「その List 自体を書き換える」ので、元の順番が不要なときに向いている
という道具が揃っています。
大事なのは、「何を基準に」「どんな優先順位で」並べたいのかを、
まず日本語でハッキリさせてから、それを OrderBy / ThenBy に落とし込むことです。
そこさえブレなければ、ソートはとても素直で強力な“業務ユーティリティ”になります。
