C# LINQ OrderByの使い方を徹底解説|昇順・降順・複数条件ソートまでサンプルコード付き

はじめに

C#でコレクションのデータを並び替えたいときによく使われるのが、LINQのOrderByです。OrderByを使うと、Listや配列、オブジェクトの一覧などを、数値順・文字列順・日付順などで簡単にソートできます。

たとえば、ユーザー一覧を年齢順に並び替えたり、商品一覧を価格の安い順に表示したり、売上データを日付順に整理したりする場面で役立ちます。

この記事では、C# LINQのOrderByについて、基本的な使い方から、OrderByDescendingによる降順ソート、ThenByを使った複数条件ソート、Dictionaryの並び替え、遅延実行、よくあるエラーまで、サンプルコード付きでわかりやすく解説します。

1. C# LINQのOrderByとは

1-1. OrderByの基本的な役割

OrderByは、C#のLINQでデータを昇順に並び替えるためのメソッドです。

LINQとは、コレクションや配列などのデータに対して、検索・抽出・並び替え・集計などを統一的な書き方で行える仕組みです。その中でもOrderByは、指定したキーをもとにデータを小さい順、または辞書順に並び替えるときに使います。

基本的なイメージは次のとおりです。

C#
var sorted = items.OrderBy(item => item);

このコードでは、itemsの要素を昇順に並び替えた結果をsortedに格納しています。

1-2. LINQでソート処理を行うメリット

LINQのOrderByを使うメリットは、コードがシンプルで読みやすくなることです。

たとえば、従来のように比較処理を自分で細かく書く必要がなく、次のように1行で並び替えを表現できます。

C#
var sortedUsers = users.OrderBy(user => user.Age);

このコードを見るだけで、「ユーザー一覧を年齢順に並び替えている」とすぐに理解できます。

また、WhereSelectなど他のLINQメソッドと組み合わせやすい点も大きなメリットです。

C#
var result = users
.Where(user => user.IsActive)
.OrderBy(user => user.Age)
.Select(user => user.Name);

このように、抽出、並び替え、変換を流れるように書けます。

1-3. OrderByを使える主なデータ型

OrderByは、IEnumerable<T>を実装しているコレクションに対して使用できます。

主な対象は次のようなデータです。

C#
List<int> numbers = new List<int> { 3, 1, 2 };

int[] scores = { 80, 95, 70 };

Dictionary<string, int> ages = new Dictionary<string, int>
{
{ "Taro", 25 },
{ "Hanako", 30 },
{ "Jiro", 20 }
};

List、配列、Dictionary、オブジェクトのコレクションなど、C#でよく使う多くのデータに対してOrderByを利用できます。

1-4. OrderByとSQLのORDER BYの違い

C# LINQのOrderByは、SQLのORDER BYに似ています。どちらもデータを指定した条件で並び替えるために使います。

SQLでは次のように書きます。

SQL
SELECT * FROM Users
ORDER BY Age;

C# LINQでは次のように書きます。

C#
var sortedUsers = users.OrderBy(user => user.Age);

考え方は似ていますが、LINQのOrderByはC#のオブジェクトやコレクションに対して使う点が特徴です。また、LINQ to Objectsではメモリ上のデータを並び替えます。一方、LINQ to SQLやEntity Frameworkでは、LINQのOrderByがSQLのORDER BYに変換され、データベース側でソートされることがあります。

2. OrderByの基本的な使い方

2-1. OrderByで昇順に並び替える基本構文

OrderByの基本構文は次のとおりです。

C#
var sorted = collection.OrderBy(x => x);

オブジェクトのプロパティを基準にする場合は、次のように書きます。

C#
var sorted = collection.OrderBy(x => x.PropertyName);

x => x.PropertyNameの部分はラムダ式です。並び替えの基準となる値を指定します。

2-2. 数値を昇順でソートするサンプルコード

数値を小さい順に並び替える例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
List<int> numbers = new List<int> { 5, 2, 8, 1, 3 };

var sortedNumbers = numbers.OrderBy(n => n);

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
}
}

実行結果は次のようになります。

1
2
3
5
8

OrderBy(n => n)と書くことで、数値そのものを基準に昇順でソートしています。

2-3. 文字列を昇順でソートするサンプルコード

文字列を昇順に並び替える場合も、基本的な書き方は同じです。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
List<string> names = new List<string> { "Sato", "Tanaka", "Aoki", "Suzuki" };

var sortedNames = names.OrderBy(name => name);

foreach (var name in sortedNames)
{
Console.WriteLine(name);
}
}
}

実行結果は次のようになります。

Aoki
Sato
Suzuki
Tanaka

文字列の場合は、既定の文字列比較に従って並び替えられます。

2-4. オブジェクトのプロパティを指定してソートする方法

実務では、単純な数値や文字列よりも、オブジェクトの一覧を特定のプロパティで並び替える場面が多くあります。

次の例では、ユーザー一覧を年齢順に並び替えます。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class User
{
public string Name { get; set; }
public int Age { get; set; }
}

class Program
{
static void Main()
{
List<User> users = new List<User>
{
new User { Name = "Taro", Age = 30 },
new User { Name = "Hanako", Age = 25 },
new User { Name = "Jiro", Age = 20 }
};

var sortedUsers = users.OrderBy(user => user.Age);

foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
}
}

実行結果は次のようになります。

Jiro: 20
Hanako: 25
Taro: 30

OrderBy(user => user.Age)とすることで、Ageプロパティを基準に昇順でソートできます。

2-5. ラムダ式を使ったOrderByの書き方

OrderByでは、ラムダ式を使ってソートキーを指定するのが一般的です。

C#
var sorted = users.OrderBy(user => user.Age);

このラムダ式は、「各userからAgeを取り出し、その値を基準に並び替える」という意味です。

文字列の長さでソートすることもできます。

C#
var sortedNames = names.OrderBy(name => name.Length);

この場合、名前の文字数が短い順に並び替えられます。

C#
List<string> names = new List<string> { "Tom", "Alexander", "Bob", "Mike" };

var sortedNames = names.OrderBy(name => name.Length);

foreach (var name in sortedNames)
{
Console.WriteLine(name);
}

実行結果は次のようになります。

Tom
Bob
Mike
Alexander

3. OrderByDescendingで降順に並び替える方法

3-1. OrderByDescendingの基本構文

降順で並び替えたい場合は、OrderByDescendingを使います。

基本構文は次のとおりです。

C#
var sorted = collection.OrderByDescending(x => x);

オブジェクトのプロパティを基準にする場合は、次のように書きます。

C#
var sorted = collection.OrderByDescending(x => x.PropertyName);

OrderByが昇順であるのに対して、OrderByDescendingは降順です。

3-2. 数値を降順でソートするサンプルコード

数値を大きい順に並び替える例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
List<int> numbers = new List<int> { 5, 2, 8, 1, 3 };

var sortedNumbers = numbers.OrderByDescending(n => n);

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
}
}

実行結果は次のようになります。

8
5
3
2
1

3-3. 文字列を降順でソートするサンプルコード

文字列を降順に並び替える場合も、OrderByDescendingを使います。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
List<string> names = new List<string> { "Sato", "Tanaka", "Aoki", "Suzuki" };

var sortedNames = names.OrderByDescending(name => name);

foreach (var name in sortedNames)
{
Console.WriteLine(name);
}
}
}

実行結果は次のようになります。

Tanaka
Suzuki
Sato
Aoki

文字列の場合も、既定の比較ルールに基づいて逆順に並び替えられます。

3-4. オブジェクトのプロパティを降順でソートする方法

オブジェクトのプロパティを基準に降順ソートする例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Product
{
public string Name { get; set; }
public int Price { get; set; }
}

class Program
{
static void Main()
{
List<Product> products = new List<Product>
{
new Product { Name = "Keyboard", Price = 3000 },
new Product { Name = "Mouse", Price = 1500 },
new Product { Name = "Monitor", Price = 25000 }
};

var sortedProducts = products.OrderByDescending(product => product.Price);

foreach (var product in sortedProducts)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
}
}

実行結果は次のようになります。

Monitor: 25000円
Keyboard: 3000円
Mouse: 1500円

価格の高い順に商品を表示したい場合などに便利です。

3-5. OrderByとOrderByDescendingの使い分け

OrderByOrderByDescendingは、並び替えたい方向によって使い分けます。

昇順にしたい場合はOrderByを使います。

C#
var sorted = products.OrderBy(product => product.Price);

降順にしたい場合はOrderByDescendingを使います。

C#
var sorted = products.OrderByDescending(product => product.Price);

価格の安い順、年齢の若い順、日付の古い順にしたい場合はOrderByを使い、価格の高い順、年齢の高い順、日付の新しい順にしたい場合はOrderByDescendingを使うと考えるとわかりやすいです。

4. ThenBy・ThenByDescendingで複数条件ソートする方法

4-1. 複数条件ソートが必要になるケース

データを並び替えるとき、1つの条件だけでは順序が決まらないことがあります。

たとえば、ユーザー一覧を年齢順に並び替える場合、同じ年齢のユーザーが複数いるかもしれません。そのような場合に、年齢が同じなら名前順に並び替える、といった第2条件を指定できます。

このような複数条件ソートには、ThenByThenByDescendingを使います。

4-2. ThenByで第2条件を昇順ソートする方法

ThenByは、OrderByで指定した第1条件が同じ場合に、第2条件を昇順で適用するためのメソッドです。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name);

このコードでは、まずAgeの昇順で並び替え、年齢が同じ場合はNameの昇順で並び替えます。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class User
{
public string Name { get; set; }
public int Age { get; set; }
}

class Program
{
static void Main()
{
List<User> users = new List<User>
{
new User { Name = "Taro", Age = 25 },
new User { Name = "Hanako", Age = 20 },
new User { Name = "Jiro", Age = 25 },
new User { Name = "Aiko", Age = 20 }
};

var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name);

foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
}
}

実行結果は次のようになります。

Aiko: 20
Hanako: 20
Jiro: 25
Taro: 25

4-3. ThenByDescendingで第2条件を降順ソートする方法

第2条件を降順にしたい場合は、ThenByDescendingを使います。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenByDescending(user => user.Name);

このコードでは、年齢は昇順、名前は降順で並び替えます。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenByDescending(user => user.Name);

foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}

たとえば同じ年齢の中で名前を逆順にしたい場合に使います。

4-4. OrderByを複数回使うとどうなるか

複数条件ソートをしたいときに、次のようにOrderByを複数回書いてしまうケースがあります。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.OrderBy(user => user.Name);

この書き方では、最初のOrderBy(user => user.Age)の並び替えが、第2の条件として扱われるわけではありません。後から呼び出したOrderBy(user => user.Name)が新しい主条件になります。

複数条件でソートしたい場合は、2回目以降にThenByまたはThenByDescendingを使います。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name);

この違いは、C# LINQのOrderByでよくある間違いなので注意しましょう。

4-5. 複数条件ソートの実践サンプルコード

次の例では、部署名を昇順、給与を降順で並び替えます。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Employee
{
public string Name { get; set; }
public string Department { get; set; }
public int Salary { get; set; }
}

class Program
{
static void Main()
{
List<Employee> employees = new List<Employee>
{
new Employee { Name = "Sato", Department = "Sales", Salary = 400000 },
new Employee { Name = "Suzuki", Department = "Development", Salary = 500000 },
new Employee { Name = "Tanaka", Department = "Sales", Salary = 450000 },
new Employee { Name = "Yamada", Department = "Development", Salary = 480000 }
};

var sortedEmployees = employees
.OrderBy(employee => employee.Department)
.ThenByDescending(employee => employee.Salary);

foreach (var employee in sortedEmployees)
{
Console.WriteLine($"{employee.Department} - {employee.Name}: {employee.Salary}");
}
}
}

実行結果は次のようになります。

Development - Suzuki: 500000
Development - Yamada: 480000
Sales - Tanaka: 450000
Sales - Sato: 400000

部署ごとにまとめつつ、同じ部署内では給与が高い順に並び替えられています。

5. List・配列・DictionaryでOrderByを使う方法

5-1. ListをOrderByで並び替える

List<T>は、OrderByを使う代表的なコレクションです。

C#
List<int> numbers = new List<int> { 4, 1, 3, 2 };

var sortedNumbers = numbers.OrderBy(n => n);

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}

実行結果は次のようになります。

1
2
3
4

ただし、OrderByは元のList自体を変更しません。ソート済みのListとして扱いたい場合は、ToList()を使います。

C#
List<int> sortedList = numbers.OrderBy(n => n).ToList();

5-2. 配列をOrderByで並び替える

配列に対してもOrderByを使えます。

C#
int[] numbers = { 9, 3, 7, 1 };

var sortedNumbers = numbers.OrderBy(n => n);

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}

実行結果は次のようになります。

1
3
7
9

配列として結果を受け取りたい場合は、ToArray()を使います。

C#
int[] sortedArray = numbers.OrderBy(n => n).ToArray();

5-3. Dictionaryをキーでソートする

Dictionary<TKey, TValue>をキーでソートする場合は、Keyを指定します。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
static void Main()
{
Dictionary<string, int> scores = new Dictionary<string, int>
{
{ "Taro", 80 },
{ "Hanako", 95 },
{ "Jiro", 70 }
};

var sortedByKey = scores.OrderBy(pair => pair.Key);

foreach (var pair in sortedByKey)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}
}
}

実行結果は次のようになります。

Hanako: 95
Jiro: 70
Taro: 80

キーである名前の昇順で並び替えられています。

5-4. Dictionaryを値でソートする

Dictionaryを値でソートする場合は、Valueを指定します。

C#
var sortedByValue = scores.OrderBy(pair => pair.Value);

foreach (var pair in sortedByValue)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}

実行結果は次のようになります。

Jiro: 70
Taro: 80
Hanako: 95

点数の低い順に並び替えられます。

降順にしたい場合は、OrderByDescendingを使います。

C#
var sortedByValueDesc = scores.OrderByDescending(pair => pair.Value);

5-5. ソート結果をListや配列に変換する方法

OrderByの結果は、そのままでもforeachで処理できますが、Listや配列として保持したい場合は、ToList()ToArray()を使います。

C#
List<int> sortedList = numbers.OrderBy(n => n).ToList();
C#
int[] sortedArray = numbers.OrderBy(n => n).ToArray();

Dictionaryをソートした結果を再びDictionaryに変換することもできます。

C#
var sortedDictionary = scores
.OrderBy(pair => pair.Value)
.ToDictionary(pair => pair.Key, pair => pair.Value);

ただし、通常のDictionaryは順序を主目的としたコレクションではありません。順序を保ったまま扱いたい場合は、ソート結果をList<KeyValuePair<TKey, TValue>>として保持する方がわかりやすい場合があります。

C#
var sortedList = scores
.OrderBy(pair => pair.Value)
.ToList();

6. OrderByの戻り値と遅延実行の仕組み

6-1. OrderByの戻り値はIOrderedEnumerable

LINQのOrderByの戻り値は、IOrderedEnumerable<T>です。

C#
IOrderedEnumerable<int> sortedNumbers = numbers.OrderBy(n => n);

IOrderedEnumerable<T>は、並び替えられた列挙可能なデータを表します。ThenByThenByDescendingは、このIOrderedEnumerable<T>に対して追加の並び替え条件を指定するために使います。

6-2. OrderByは元のコレクションを変更しない

OrderByで特に重要なのは、元のコレクションを直接変更しないという点です。

C#
List<int> numbers = new List<int> { 3, 1, 2 };

var sortedNumbers = numbers.OrderBy(n => n);

Console.WriteLine(string.Join(", ", numbers));

実行結果は次のようになります。

3, 1, 2

元のnumbersは並び替えられていません。

ソートされた結果を新しいListとして使いたい場合は、次のようにします。

C#
numbers = numbers.OrderBy(n => n).ToList();

6-3. ToListやToArrayでソート結果を確定する方法

OrderByは遅延実行されます。つまり、OrderByを書いた時点では、まだ実際の並び替えが行われていない場合があります。

結果を確定したい場合は、ToList()ToArray()を使います。

C#
List<int> sortedList = numbers.OrderBy(n => n).ToList();
C#
int[] sortedArray = numbers.OrderBy(n => n).ToArray();

ToList()ToArray()を呼び出すことで、その時点のデータをもとにソート結果が作成されます。

6-4. 遅延実行で注意すべきポイント

遅延実行では、OrderByの結果を列挙するタイミングで処理が実行されます。そのため、OrderByを呼び出したあとに元のデータを変更すると、変更後のデータがソート対象になることがあります。

C#
List<int> numbers = new List<int> { 3, 1, 2 };

var sortedNumbers = numbers.OrderBy(n => n);

numbers.Add(0);

foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}

実行結果は次のようになります。

0
1
2
3

OrderByを書いた時点ではなく、foreachで列挙した時点のnumbersが使われています。

変更前の結果を固定したい場合は、すぐにToList()を呼び出します。

C#
var sortedNumbers = numbers.OrderBy(n => n).ToList();

6-5. List.Sortとの違い

OrderByList.Sortは、どちらもソートに使えますが、動作が異なります。

OrderByは元のコレクションを変更せず、新しい並び替え結果を返します。

C#
var sorted = numbers.OrderBy(n => n).ToList();

一方、List.Sortは元のList自体を直接並び替えます。

C#
numbers.Sort();

元のリストを変更したくない場合はOrderBy、元のリストそのものを並び替えたい場合はList.Sortが適しています。

オブジェクトのプロパティで並び替える場合、OrderByの方が直感的に書けることが多いです。

C#
var sortedUsers = users.OrderBy(user => user.Age).ToList();

7. カスタム条件でOrderByを使う方法

7-1. 複数プロパティを組み合わせてソートキーを作る

OrderByでは、1つのプロパティだけでなく、複数の値を組み合わせたソートキーを作ることもできます。

たとえば、姓と名を結合して並び替える例です。

C#
var sortedUsers = users.OrderBy(user => user.LastName + user.FirstName);

匿名型を使って複数のキーをまとめることもできます。

C#
var sortedUsers = users.OrderBy(user => new { user.LastName, user.FirstName });

ただし、複数条件ソートとして明確に書きたい場合は、ThenByを使う方が読みやすいです。

C#
var sortedUsers = users
.OrderBy(user => user.LastName)
.ThenBy(user => user.FirstName);

7-2. nullを含むデータをソートする方法

データにnullが含まれる場合は、null参照に注意が必要です。

たとえば、次のようなコードはNamenullでも文字列自体の比較は可能ですが、Name.Lengthのようにプロパティへアクセスすると例外が発生する可能性があります。

C#
var sortedUsers = users.OrderBy(user => user.Name.Length);

安全に書くには、null条件演算子やnull合体演算子を使います。

C#
var sortedUsers = users.OrderBy(user => user.Name?.Length ?? 0);

Namenullの場合は長さを0として扱います。

また、nullを最後に並べたい場合は、次のように書けます。

C#
var sortedUsers = users
.OrderBy(user => user.Name == null)
.ThenBy(user => user.Name);

Name == nullfalseのデータが先に来て、trueのデータ、つまりnullが後に並びます。

7-3. 大文字・小文字を区別せずにソートする方法

文字列をソートするとき、大文字と小文字を区別したくない場合があります。

簡単な方法は、ToLower()ToUpper()を使うことです。

C#
var sortedNames = names.OrderBy(name => name.ToLower());

ただし、文字列比較の意図を明確にしたい場合は、StringComparerを使う方法もあります。

C#
var sortedNames = names.OrderBy(name => name, StringComparer.OrdinalIgnoreCase);

このコードでは、大文字・小文字を区別せずに文字列を昇順で並び替えます。

7-4. 日付をOrderByでソートする方法

DateTimeのプロパティを指定すれば、日付順にソートできます。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Sale
{
public DateTime Date { get; set; }
public int Amount { get; set; }
}

class Program
{
static void Main()
{
List<Sale> sales = new List<Sale>
{
new Sale { Date = new DateTime(2024, 3, 10), Amount = 10000 },
new Sale { Date = new DateTime(2024, 1, 15), Amount = 8000 },
new Sale { Date = new DateTime(2024, 2, 20), Amount = 12000 }
};

var sortedSales = sales.OrderBy(sale => sale.Date);

foreach (var sale in sortedSales)
{
Console.WriteLine($"{sale.Date:yyyy/MM/dd}: {sale.Amount}");
}
}
}

実行結果は次のようになります。

2024/01/15: 8000
2024/02/20: 12000
2024/03/10: 10000

新しい日付順にしたい場合は、OrderByDescendingを使います。

C#
var sortedSales = sales.OrderByDescending(sale => sale.Date);

7-5. 独自Comparerを使ったカスタムソート

標準の比較ではなく、独自のルールでソートしたい場合は、IComparer<T>を使えます。

次の例では、文字列の長さで比較し、長さが同じ場合は通常の文字列比較を行います。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class StringLengthComparer : IComparer<string>
{
public int Compare(string x, string y)
{
int lengthCompare = x.Length.CompareTo(y.Length);

if (lengthCompare != 0)
{
return lengthCompare;
}

return string.Compare(x, y, StringComparison.Ordinal);
}
}

class Program
{
static void Main()
{
List<string> names = new List<string> { "Bob", "Alice", "Tom", "David" };

var sortedNames = names.OrderBy(name => name, new StringLengthComparer());

foreach (var name in sortedNames)
{
Console.WriteLine(name);
}
}
}

実行結果は次のようになります。

Bob
Tom
Alice
David

独自Comparerを使うと、業務ルールに合わせた柔軟な並び替えができます。

8. LINQ OrderByでよくあるエラーと注意点

8-1. OrderByの結果が元のListに反映されない

OrderByでよくあるミスは、元のListが直接並び替わると思ってしまうことです。

C#
numbers.OrderBy(n => n);

このコードだけでは、ソート結果はどこにも保存されません。

正しくは、結果を変数に代入します。

C#
var sortedNumbers = numbers.OrderBy(n => n).ToList();

元の変数に再代入することもできます。

C#
numbers = numbers.OrderBy(n => n).ToList();

8-2. OrderByを複数回使って意図しない順序になる

複数条件で並び替えたい場合に、OrderByを連続して使うと意図しない結果になることがあります。

C#
var result = users
.OrderBy(user => user.Age)
.OrderBy(user => user.Name);

この場合、最終的な主条件はNameになります。Ageを第1条件、Nameを第2条件にしたい場合は、次のように書きます。

C#
var result = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name);

2つ目以降の条件には、ThenByまたはThenByDescendingを使いましょう。

8-3. null参照で例外が発生する

ソートキーの中でnullのプロパティにアクセスすると、NullReferenceExceptionが発生することがあります。

C#
var sortedUsers = users.OrderBy(user => user.Name.Length);

Namenullの場合、このコードは危険です。

安全に書くには、次のようにします。

C#
var sortedUsers = users.OrderBy(user => user.Name?.Length ?? 0);

また、オブジェクト自体がnullの可能性がある場合は、さらに注意が必要です。

C#
var sortedUsers = users.OrderBy(user => user?.Name ?? "");

8-4. ソート後にToListを忘れる

OrderByの結果をList<T>として扱いたい場合、ToList()を忘れると型の違いで困ることがあります。

C#
var sortedUsers = users.OrderBy(user => user.Age);

この場合、sortedUsersList<User>ではなく、IOrderedEnumerable<User>です。

List<User>として扱いたい場合は、次のようにします。

C#
List<User> sortedUsers = users.OrderBy(user => user.Age).ToList();

配列にしたい場合は、ToArray()を使います。

C#
User[] sortedUsers = users.OrderBy(user => user.Age).ToArray();

8-5. パフォーマンスに注意すべきケース

OrderByは便利ですが、大量データに対して何度も実行するとパフォーマンスに影響することがあります。

たとえば、ループの中で毎回OrderByを呼び出すと、不要なソート処理が繰り返されます。

C#
foreach (var item in items)
{
var sorted = users.OrderBy(user => user.Age).ToList();
}

このような場合は、ループの外で一度だけソートしましょう。

C#
var sortedUsers = users.OrderBy(user => user.Age).ToList();

foreach (var item in items)
{
// sortedUsersを使う
}

また、データベースから取得する場合は、可能であれば必要な条件で絞り込んでからソートするなど、処理対象を減らす工夫も重要です。

9. OrderByの実践例

9-1. ユーザー一覧を年齢順に並び替える

ユーザー一覧を年齢の若い順に並び替える例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class User
{
public string Name { get; set; }
public int Age { get; set; }
}

class Program
{
static void Main()
{
List<User> users = new List<User>
{
new User { Name = "Taro", Age = 30 },
new User { Name = "Hanako", Age = 22 },
new User { Name = "Jiro", Age = 25 }
};

var sortedUsers = users.OrderBy(user => user.Age).ToList();

foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
}
}

実行結果は次のようになります。

Hanako: 22
Jiro: 25
Taro: 30

9-2. 商品一覧を価格順に並び替える

商品を価格の安い順に並び替える例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class Product
{
public string Name { get; set; }
public int Price { get; set; }
}

class Program
{
static void Main()
{
List<Product> products = new List<Product>
{
new Product { Name = "Laptop", Price = 120000 },
new Product { Name = "Mouse", Price = 2000 },
new Product { Name = "Keyboard", Price = 8000 }
};

var sortedProducts = products.OrderBy(product => product.Price).ToList();

foreach (var product in sortedProducts)
{
Console.WriteLine($"{product.Name}: {product.Price}円");
}
}
}

実行結果は次のようになります。

Mouse: 2000円
Keyboard: 8000円
Laptop: 120000円

価格の高い順にしたい場合は、OrderByDescendingを使います。

C#
var sortedProducts = products.OrderByDescending(product => product.Price).ToList();

9-3. 売上データを日付順に並び替える

売上データを日付の古い順に並び替える例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class SalesRecord
{
public DateTime Date { get; set; }
public int Amount { get; set; }
}

class Program
{
static void Main()
{
List<SalesRecord> records = new List<SalesRecord>
{
new SalesRecord { Date = new DateTime(2024, 5, 1), Amount = 30000 },
new SalesRecord { Date = new DateTime(2024, 4, 15), Amount = 25000 },
new SalesRecord { Date = new DateTime(2024, 5, 10), Amount = 40000 }
};

var sortedRecords = records.OrderBy(record => record.Date).ToList();

foreach (var record in sortedRecords)
{
Console.WriteLine($"{record.Date:yyyy/MM/dd}: {record.Amount}円");
}
}
}

実行結果は次のようになります。

2024/04/15: 25000円
2024/05/01: 30000円
2024/05/10: 40000円

9-4. 名前順・年齢順で複数条件ソートする

名前順に並び替え、同じ名前の場合は年齢順にする例です。

C#
using System;
using System.Collections.Generic;
using System.Linq;

class User
{
public string Name { get; set; }
public int Age { get; set; }
}

class Program
{
static void Main()
{
List<User> users = new List<User>
{
new User { Name = "Sato", Age = 30 },
new User { Name = "Tanaka", Age = 25 },
new User { Name = "Sato", Age = 22 },
new User { Name = "Aoki", Age = 28 }
};

var sortedUsers = users
.OrderBy(user => user.Name)
.ThenBy(user => user.Age)
.ToList();

foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
}
}

実行結果は次のようになります。

Aoki: 28
Sato: 22
Sato: 30
Tanaka: 25

OrderByで名前を昇順にし、ThenByで年齢を昇順にしています。

9-5. LINQクエリ構文でOrderByを書く方法

LINQには、メソッド構文のほかにクエリ構文があります。

メソッド構文では次のように書きます。

C#
var sortedUsers = users.OrderBy(user => user.Age);

クエリ構文では次のように書きます。

C#
var sortedUsers =
from user in users
orderby user.Age
select user;

降順にしたい場合は、descendingを付けます。

C#
var sortedUsers =
from user in users
orderby user.Age descending
select user;

複数条件も指定できます。

C#
var sortedUsers =
from user in users
orderby user.Age, user.Name
select user;

メソッド構文とクエリ構文のどちらを使っても問題ありませんが、C#の実務ではメソッド構文のOrderByThenByがよく使われます。

10. OrderByに関するよくある質問

10-1. OrderByとSortの違いは何ですか

OrderByはLINQのメソッドで、元のコレクションを変更せずに、並び替えた結果を返します。

C#
var sorted = numbers.OrderBy(n => n).ToList();

一方、List.Sortは元のList自体を直接並び替えます。

C#
numbers.Sort();

元のデータを変更したくない場合はOrderBy、元のListをそのまま並び替えたい場合はSortを使うとよいでしょう。

10-2. OrderByは昇順ですか降順ですか

OrderByは昇順です。

C#
var sorted = numbers.OrderBy(n => n);

数値であれば小さい順、文字列であれば辞書順、日付であれば古い順に並び替えられます。

降順にしたい場合は、OrderByDescendingを使います。

C#
var sorted = numbers.OrderByDescending(n => n);

10-3. OrderByの後にWhereを使えますか

OrderByの後にWhereを使うことはできます。

C#
var result = users
.OrderBy(user => user.Age)
.Where(user => user.Age >= 20);

ただし、一般的には先にWhereで絞り込んでからOrderByで並び替える方が効率的です。

C#
var result = users
.Where(user => user.Age >= 20)
.OrderBy(user => user.Age);

処理対象を減らしてからソートすることで、無駄な並び替えを避けやすくなります。

10-4. OrderByで元のListを直接並び替えられますか

OrderByは元のListを直接並び替えません。

C#
numbers.OrderBy(n => n);

このコードだけでは、numbersの順序は変わりません。

元の変数にソート結果を反映したい場合は、次のように再代入します。

C#
numbers = numbers.OrderBy(n => n).ToList();

元のListそのものを直接並び替えたい場合は、List.Sortを使います。

C#
numbers.Sort();

10-5. 複数条件でソートするにはどうすればよいですか

複数条件でソートする場合は、最初の条件にOrderByまたはOrderByDescendingを使い、2つ目以降の条件にThenByまたはThenByDescendingを使います。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name);

この例では、年齢の昇順で並び替え、年齢が同じ場合は名前の昇順で並び替えます。

第2条件を降順にしたい場合は、ThenByDescendingを使います。

C#
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenByDescending(user => user.Name);

複数条件ソートでは、OrderByを何度も使うのではなく、ThenByを使うのがポイントです。

まとめ

C# LINQのOrderByは、コレクションを昇順に並び替えるための便利なメソッドです。数値、文字列、日付、オブジェクトのプロパティなど、さまざまなデータを簡単にソートできます。

昇順で並び替える場合はOrderBy、降順で並び替える場合はOrderByDescendingを使います。複数条件でソートしたい場合は、最初にOrderByを使い、2つ目以降の条件にはThenByThenByDescendingを使います。

また、OrderByは元のコレクションを直接変更しない点にも注意が必要です。ソート結果をListや配列として確定したい場合は、ToList()ToArray()を使いましょう。

C#でデータの並び替えを行う場面は非常に多くあります。OrderByOrderByDescendingThenByThenByDescendingを正しく使い分けることで、読みやすく保守しやすいソート処理を書けるようになります。