C# ListをOrderByで並び替える方法|昇順・降順・複数条件・元のリスト変更まで解説
はじめに
C#でList<T>の要素を並び替えたいときによく使うのが、LINQのOrderByです。
OrderByを使うと、数値のリストを小さい順に並べたり、文字列をアルファベット順に並べたり、オブジェクトのリストを「年齢順」「名前順」「日付順」などで簡単に並び替えられます。
ただし、OrderByにはいくつか注意点があります。特に初心者がつまずきやすいのが、次のような点です。
OrderByは元のListを直接変更しないこと、戻り値がList<T>ではないこと、複数条件で並び替えるときはThenByを使うことなどです。
この記事では、C#のListをOrderByで並び替える方法を、昇順・降順・複数条件・元のリストを変更する方法まで、サンプルコード付きでわかりやすく解説します。
1. C#のListをOrderByで並び替える基本
1-1. OrderByとは何か
OrderByは、LINQで提供されている並び替え用のメソッドです。
指定した条件に従って、コレクションの要素を昇順に並び替えます。
たとえば、数値のリストを小さい順に並べる場合は次のように書きます。
C#using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 3, 1, 5, 2, 4 };
var sortedNumbers = numbers.OrderBy(x => x).ToList();
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
実行結果は次のようになります。
C#1
2
3
4
5
OrderBy(x => x)の部分では、「各要素そのものを基準にして昇順で並び替える」という意味になります。
1-2. List<T>を並び替えるときにOrderByを使う場面
OrderByは、List<T>を特定の条件で並び替えたいときに使います。
たとえば、次のような場面でよく使われます。
数値のリストを小さい順に並べたいとき、文字列のリストを名前順に並べたいとき、ユーザー一覧を年齢順に並べたいとき、商品一覧を価格順に並べたいとき、日付のリストを古い順に並べたいときなどです。
特に、オブジェクトのリストをプロパティで並び替える場合にOrderByは便利です。
C#var users = new List<User>
{
new User { Name = "Tanaka", Age = 30 },
new User { Name = "Sato", Age = 20 },
new User { Name = "Suzuki", Age = 25 }
};
var sortedUsers = users.OrderBy(user => user.Age).ToList();
このコードでは、UserオブジェクトのAgeプロパティを基準にして、年齢が若い順に並び替えています。
1-3. OrderByを使うために必要なusing System.Linq
OrderByを使うには、基本的にファイルの先頭に次のusingが必要です。
C#using System.Linq;
OrderByはLINQの拡張メソッドなので、System.Linq名前空間を読み込んでいないと使えません。
たとえば、次のようなコードを書いたときに、
C#var sortedNumbers = numbers.OrderBy(x => x).ToList();
OrderByが見つからないというエラーが出る場合は、using System.Linq;が不足している可能性があります。
C#using System;
using System.Collections.Generic;
using System.Linq;
.NET 6以降のプロジェクトでは、テンプレートによって暗黙的なusingが有効になっていることもあります。その場合は明示的に書かなくても使えることがありますが、学習段階ではusing System.Linq;が必要だと覚えておくとよいでしょう。
1-4. OrderByの戻り値はListではなくIOrderedEnumerableである点
OrderByを使うと、戻り値はList<T>ではありません。
戻り値の型は、主に次のような型になります。
C#IOrderedEnumerable<T>
そのため、並び替えた結果をList<T>として扱いたい場合は、最後にToList()を付けるのが一般的です。
C#var numbers = new List<int> { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x);
この時点のsortedNumbersはList<int>ではありません。
List<int>として使いたい場合は、次のようにします。
C#List<int> sortedNumbers = numbers.OrderBy(x => x).ToList();
OrderByを使ったあとに、別のリストとして保存したい場合は、ToList()を忘れないようにしましょう。
2. ListをOrderByで昇順に並び替える方法
2-1. 数値のListを昇順に並び替える基本コード
数値のList<int>を昇順に並び替えるには、次のように書きます。
C#using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 50, 10, 30, 20, 40 };
var sortedNumbers = numbers.OrderBy(x => x).ToList();
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
実行結果は次のとおりです。
C#10
20
30
40
50
OrderBy(x => x)は、リストの各要素をそのまま比較対象にする書き方です。
intやdoubleなどの数値であれば、小さい値から大きい値へ並び替えられます。
C#var scores = new List<double> { 82.5, 91.0, 75.3, 88.8 };
var sortedScores = scores.OrderBy(score => score).ToList();
このように、数値リストの昇順ソートでは、OrderBy(x => x)が基本形になります。
2-2. 文字列のListを昇順に並び替える基本コード
文字列のList<string>もOrderByで昇順に並び替えられます。
C#using System;
using System.Collections.Generic;
using System.Linq;
var names = new List<string> { "Tanaka", "Sato", "Suzuki", "Abe" };
var sortedNames = names.OrderBy(name => name).ToList();
foreach (var name in sortedNames)
{
Console.WriteLine(name);
}
実行結果は次のようになります。
C#Abe
Sato
Suzuki
Tanaka
文字列の場合は、通常、文字コードやカルチャの規則に基づいて並び替えられます。
日本語の文字列も並び替えできます。
C#var fruits = new List<string> { "りんご", "みかん", "バナナ", "いちご" };
var sortedFruits = fruits.OrderBy(fruit => fruit).ToList();
ただし、日本語の五十音順として完全に期待通りになるとは限りません。日本語の自然な読み順で並び替えたい場合は、読み仮名を別プロパティとして持たせて、その読み仮名でソートする方法がよく使われます。
2-3. オブジェクトのListをプロパティで昇順に並び替える方法
OrderByが特に便利なのは、オブジェクトのリストを特定のプロパティで並び替える場合です。
次のようなUserクラスがあるとします。
C#public class User
{
public string Name { get; set; } = "";
public int Age { get; set; }
}
年齢順に並び替える場合は、次のように書きます。
C#var users = new List<User>
{
new User { Name = "Tanaka", Age = 30 },
new User { Name = "Sato", Age = 20 },
new User { Name = "Suzuki", Age = 25 }
};
var sortedUsers = users.OrderBy(user => user.Age).ToList();
foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
実行結果は次のようになります。
C#Sato: 20
Suzuki: 25
Tanaka: 30
OrderBy(user => user.Age)の部分で、Ageプロパティを基準に昇順で並び替えています。
名前順に並び替える場合は、次のようにします。
C#var sortedUsers = users.OrderBy(user => user.Name).ToList();
日付順に並び替える場合も同じ考え方です。
C#var sortedItems = items.OrderBy(item => item.CreatedAt).ToList();
このように、OrderByではラムダ式を使って「何を基準に並び替えるか」を指定します。
2-4. OrderBy後にToListでListに変換する方法
OrderByの結果をList<T>として扱いたい場合は、最後にToList()を付けます。
C#var sortedNumbers = numbers.OrderBy(x => x).ToList();
ToList()を付けない場合でも、foreachで回すことはできます。
C#var sortedNumbers = numbers.OrderBy(x => x);
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
しかし、次のようにList<int>型の変数へ代入しようとすると、ToList()が必要です。
C#List<int> sortedNumbers = numbers.OrderBy(x => x).ToList();
ToList()を忘れると、次のようなコードはエラーになります。
C#List<int> sortedNumbers = numbers.OrderBy(x => x);
OrderByの結果をリストとして使いたい場合は、ToList()までセットで書くと覚えておくとよいでしょう。
3. ListをOrderByDescendingで降順に並び替える方法
3-1. 数値のListを降順に並び替える基本コード
List<T>を降順に並び替えたい場合は、OrderByDescendingを使います。
C#using System;
using System.Collections.Generic;
using System.Linq;
var numbers = new List<int> { 50, 10, 30, 20, 40 };
var sortedNumbers = numbers.OrderByDescending(x => x).ToList();
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
実行結果は次のようになります。
C#50
40
30
20
10
OrderByが昇順であるのに対して、OrderByDescendingは降順です。
大きい数値から小さい数値へ並び替えたい場合は、OrderByDescending(x => x)を使います。
3-2. 文字列のListを降順に並び替える基本コード
文字列のリストを降順に並び替える場合も、OrderByDescendingを使います。
C#var names = new List<string> { "Tanaka", "Sato", "Suzuki", "Abe" };
var sortedNames = names.OrderByDescending(name => name).ToList();
foreach (var name in sortedNames)
{
Console.WriteLine(name);
}
実行結果は次のようになります。
C#Tanaka
Suzuki
Sato
Abe
昇順の場合はAbeから始まりましたが、降順では逆方向の並びになります。
3-3. オブジェクトのListをプロパティで降順に並び替える方法
オブジェクトのリストをプロパティで降順に並び替える場合も、考え方は同じです。
次の例では、年齢が高い順にユーザーを並び替えます。
C#var users = new List<User>
{
new User { Name = "Tanaka", Age = 30 },
new User { Name = "Sato", Age = 20 },
new User { Name = "Suzuki", Age = 25 }
};
var sortedUsers = users.OrderByDescending(user => user.Age).ToList();
foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
実行結果は次のとおりです。
C#Tanaka: 30
Suzuki: 25
Sato: 20
作成日が新しい順に並び替える場合も、OrderByDescendingがよく使われます。
C#var sortedArticles = articles
.OrderByDescending(article => article.PublishedAt)
.ToList();
「新着順」「価格が高い順」「スコアが高い順」などは、OrderByDescendingを使う代表的なケースです。
3-4. OrderByとOrderByDescendingの使い分け
OrderByとOrderByDescendingの使い分けはシンプルです。
昇順にしたい場合はOrderBy、降順にしたい場合はOrderByDescendingを使います。
C#// 昇順
var ascending = numbers.OrderBy(x => x).ToList();
// 降順
var descending = numbers.OrderByDescending(x => x).ToList();
オブジェクトのリストでも同じです。
C#// 年齢が若い順
var youngFirst = users.OrderBy(user => user.Age).ToList();
// 年齢が高い順
var oldFirst = users.OrderByDescending(user => user.Age).ToList();
並び替えの基準が数値でも文字列でも日付でも、使い分けの考え方は変わりません。
4. 複数条件でListを並び替える方法
4-1. ThenByで第2条件を昇順に指定する方法
複数条件で並び替えたい場合は、OrderByのあとにThenByを使います。
たとえば、年齢順に並び替えたあと、同じ年齢の人を名前順に並び替えたい場合は次のように書きます。
C#var users = new List<User>
{
new User { Name = "Tanaka", Age = 30 },
new User { Name = "Sato", Age = 20 },
new User { Name = "Abe", Age = 20 },
new User { Name = "Suzuki", Age = 30 }
};
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();
foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: {user.Age}");
}
実行結果は次のようになります。
C#Abe: 20
Sato: 20
Suzuki: 30
Tanaka: 30
まずAgeで昇順に並び替えられ、同じAgeの中ではNameで昇順に並び替えられています。
4-2. ThenByDescendingで第2条件を降順に指定する方法
第2条件を降順にしたい場合は、ThenByDescendingを使います。
次の例では、年齢を昇順にし、同じ年齢の中ではスコアが高い順に並び替えます。
C#public class User
{
public string Name { get; set; } = "";
public int Age { get; set; }
public int Score { get; set; }
}
C#var users = new List<User>
{
new User { Name = "Tanaka", Age = 30, Score = 80 },
new User { Name = "Sato", Age = 20, Score = 90 },
new User { Name = "Abe", Age = 20, Score = 95 },
new User { Name = "Suzuki", Age = 30, Score = 70 }
};
var sortedUsers = users
.OrderBy(user => user.Age)
.ThenByDescending(user => user.Score)
.ToList();
foreach (var user in sortedUsers)
{
Console.WriteLine($"{user.Name}: Age={user.Age}, Score={user.Score}");
}
実行結果は次のようになります。
C#Abe: Age=20, Score=95
Sato: Age=20, Score=90
Tanaka: Age=30, Score=80
Suzuki: Age=30, Score=70
このように、最初の条件にはOrderByまたはOrderByDescendingを使い、2番目以降の条件にはThenByまたはThenByDescendingを使います。
4-3. OrderByを複数回書くと期待通りにならない理由
複数条件で並び替えるときに、次のようにOrderByを複数回書いてしまうことがあります。
C#var sortedUsers = users
.OrderBy(user => user.Age)
.OrderBy(user => user.Name)
.ToList();
この書き方は、年齢順に並び替えたあと、さらに名前順で並び替えるように見えます。
しかし、2回目のOrderByは新しい主条件として並び替えをやり直します。そのため、最初のOrderBy(user => user.Age)の効果が期待通りに残らないことがあります。
複数条件で並び替える場合は、次のように書くのが正しいです。
C#var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();
最初の並び替え条件にはOrderBy、追加条件にはThenByを使うと覚えておきましょう。
降順を組み合わせる場合は、次のようにします。
C#var sortedUsers = users
.OrderByDescending(user => user.Score)
.ThenBy(user => user.Name)
.ToList();
この例では、まずスコアが高い順に並び替え、同じスコアの中では名前順に並び替えます。
4-4. 複数条件ソートの実践例
実践的な例として、商品一覧を次の条件で並び替えてみます。
まずカテゴリを昇順に並び替え、同じカテゴリの中では価格を降順にし、さらに同じ価格の中では商品名を昇順にします。
C#public class Product
{
public string Category { get; set; } = "";
public string Name { get; set; } = "";
public int Price { get; set; }
}
C#var products = new List<Product>
{
new Product { Category = "Book", Name = "C#入門", Price = 3000 },
new Product { Category = "Book", Name = "LINQ実践", Price = 3500 },
new Product { Category = "PC", Name = "Mouse", Price = 2000 },
new Product { Category = "PC", Name = "Keyboard", Price = 5000 },
new Product { Category = "Book", Name = "ASP.NET", Price = 3500 }
};
var sortedProducts = products
.OrderBy(product => product.Category)
.ThenByDescending(product => product.Price)
.ThenBy(product => product.Name)
.ToList();
foreach (var product in sortedProducts)
{
Console.WriteLine($"{product.Category} / {product.Name} / {product.Price}");
}
実行結果の例は次のようになります。
C#Book / ASP.NET / 3500
Book / LINQ実践 / 3500
Book / C#入門 / 3000
PC / Keyboard / 5000
PC / Mouse / 2000
複数条件ソートでは、条件を書く順番が重要です。
最も優先したい条件をOrderByまたはOrderByDescendingで書き、その後に優先順位の低い条件をThenByまたはThenByDescendingで追加します。
5. OrderByで元のListは変更されるのか
5-1. OrderByは元のListを変更しない
OrderByを使っても、元のList自体は変更されません。
次のコードを見てみましょう。
C#var numbers = new List<int> { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x).ToList();
Console.WriteLine("元のリスト:");
foreach (var number in numbers)
{
Console.WriteLine(number);
}
Console.WriteLine("並び替え後のリスト:");
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
実行結果は次のようになります。
C#元のリスト:
3
1
2
並び替え後のリスト:
1
2
3
sortedNumbersは並び替えられていますが、元のnumbersは最初の順番のままです。
つまり、OrderByは元のリストを直接並び替えるのではなく、並び替えた結果を新しく返すメソッドです。
5-2. 並び替えた結果を新しいListに代入する方法
元のリストを残したまま、並び替えた結果を別のリストとして使いたい場合は、次のように書きます。
C#var numbers = new List<int> { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x).ToList();
この場合、numbersは元の順番を保持し、sortedNumbersに並び替え後の結果が入ります。
オブジェクトのリストでも同じです。
C#var sortedUsers = users.OrderBy(user => user.Age).ToList();
元データを残しておきたい場合や、複数の並び替えパターンを作りたい場合は、この書き方が便利です。
C#var ageAscending = users.OrderBy(user => user.Age).ToList();
var ageDescending = users.OrderByDescending(user => user.Age).ToList();
var nameAscending = users.OrderBy(user => user.Name).ToList();
このように、OrderByは元のリストを壊さずに別の並び替え結果を作れるのがメリットです。
5-3. 元のList自体を並び替えたい場合の書き方
OrderByの結果を元の変数に再代入すれば、元の変数名で並び替え後のリストを扱えます。
C#var numbers = new List<int> { 3, 1, 2 };
numbers = numbers.OrderBy(x => x).ToList();
このコードでは、numbersに並び替え後の新しいリストを代入しています。
ただし、これは元のListインスタンスを直接並び替えているわけではありません。並び替えた新しいリストを作り、それを同じ変数に入れ直しています。
変数がvarではなく明示的にList<int>として定義されている場合も同じです。
C#List<int> numbers = new List<int> { 3, 1, 2 };
numbers = numbers.OrderBy(x => x).ToList();
一方で、既存のListインスタンスそのものを並び替えたい場合は、List.Sortを使う方法があります。
C#numbers.Sort();
オブジェクトのリストを年齢順に直接並び替えるなら、次のように書けます。
C#users.Sort((a, b) => a.Age.CompareTo(b.Age));
5-4. OrderByとList.Sortの違い
OrderByとList.Sortは、どちらも並び替えに使えますが、動作に違いがあります。
OrderByは元のリストを変更せず、並び替えた結果を返します。
C#var sortedNumbers = numbers.OrderBy(x => x).ToList();
一方、List.Sortは元のリスト自体を直接並び替えます。
C#numbers.Sort();
使い分けの目安は次のとおりです。
元のリストを残したい場合はOrderBy、元のリスト自体を変更してよい場合はList.Sortが向いています。
オブジェクトのリストをわかりやすくプロパティ指定で並び替えたい場合は、OrderByのほうが読みやすいことが多いです。
C#var sortedUsers = users.OrderBy(user => user.Age).ToList();
一方、リスト自体をその場で並び替えたい場合は、Sortを使うと余計なリストを作らずに済みます。
C#users.Sort((a, b) => a.Age.CompareTo(b.Age));
読みやすさを優先するならOrderBy、元のリストを直接変更したいならSortと考えるとよいでしょう。
6. OrderByでオブジェクトのListを並び替える実践例
6-1. 年齢順に並び替える例
次のようなPersonクラスを使って、年齢順に並び替える例を見てみましょう。
C#public class Person
{
public string Name { get; set; } = "";
public int Age { get; set; }
}
C#var people = new List<Person>
{
new Person { Name = "Tanaka", Age = 35 },
new Person { Name = "Sato", Age = 22 },
new Person { Name = "Suzuki", Age = 28 }
};
var sortedPeople = people.OrderBy(person => person.Age).ToList();
foreach (var person in sortedPeople)
{
Console.WriteLine($"{person.Name}: {person.Age}");
}
実行結果は次のようになります。
C#Sato: 22
Suzuki: 28
Tanaka: 35
年齢が若い順に並び替えたい場合はOrderByを使います。
年齢が高い順にしたい場合は、OrderByDescendingを使います。
C#var sortedPeople = people.OrderByDescending(person => person.Age).ToList();
6-2. 名前順に並び替える例
名前順に並び替える場合は、Nameプロパティを指定します。
C#var people = new List<Person>
{
new Person { Name = "Tanaka", Age = 35 },
new Person { Name = "Sato", Age = 22 },
new Person { Name = "Abe", Age = 28 }
};
var sortedPeople = people.OrderBy(person => person.Name).ToList();
foreach (var person in sortedPeople)
{
Console.WriteLine($"{person.Name}: {person.Age}");
}
実行結果は次のようになります。
C#Abe: 28
Sato: 22
Tanaka: 35
名前を降順にしたい場合は、次のようにします。
C#var sortedPeople = people.OrderByDescending(person => person.Name).ToList();
日本語名を扱う場合は、漢字の名前をそのまま並び替えると期待した五十音順にならないことがあります。
その場合は、読み仮名用のプロパティを用意して、その値で並び替えると扱いやすくなります。
C#public class Person
{
public string Name { get; set; } = "";
public string Kana { get; set; } = "";
public int Age { get; set; }
}
C#var sortedPeople = people.OrderBy(person => person.Kana).ToList();
6-3. 日付順に並び替える例
日付順に並び替える場合は、DateTime型のプロパティを指定します。
C#public class Article
{
public string Title { get; set; } = "";
public DateTime PublishedAt { get; set; }
}
C#var articles = new List<Article>
{
new Article { Title = "C#入門", PublishedAt = new DateTime(2024, 5, 1) },
new Article { Title = "LINQ解説", PublishedAt = new DateTime(2024, 3, 10) },
new Article { Title = "ASP.NET基礎", PublishedAt = new DateTime(2024, 4, 20) }
};
var sortedArticles = articles
.OrderBy(article => article.PublishedAt)
.ToList();
foreach (var article in sortedArticles)
{
Console.WriteLine($"{article.PublishedAt:yyyy/MM/dd} {article.Title}");
}
実行結果は次のようになります。
C#2024/03/10 LINQ解説
2024/04/20 ASP.NET基礎
2024/05/01 C#入門
古い順に並び替えたい場合はOrderBy、新しい順に並び替えたい場合はOrderByDescendingを使います。
C#var newestArticles = articles
.OrderByDescending(article => article.PublishedAt)
.ToList();
新着記事一覧などでは、OrderByDescendingで日付の新しい順に並べることが多いです。
6-4. nullを含むプロパティを並び替えるときの注意点
オブジェクトのプロパティにnullが含まれる場合、並び替え結果が想定と異なることがあります。
たとえば、名前がnullのデータがある場合です。
C#public class Person
{
public string? Name { get; set; }
public int Age { get; set; }
}
C#var people = new List<Person>
{
new Person { Name = "Tanaka", Age = 30 },
new Person { Name = null, Age = 20 },
new Person { Name = "Sato", Age = 25 }
};
var sortedPeople = people.OrderBy(person => person.Name).ToList();
このようにnullが含まれていても並び替え自体はできますが、nullを先頭にしたいのか、末尾にしたいのかを明確にしたい場合は、条件を追加すると安全です。
nullを最後にしたい場合は、次のように書けます。
C#var sortedPeople = people
.OrderBy(person => person.Name == null)
.ThenBy(person => person.Name)
.ToList();
person.Name == nullは、Nameがnullならtrue、そうでなければfalseになります。falseのほうが先に並ぶため、nullではないデータが先、nullのデータが後になります。
また、nullの場合に空文字として扱いたいなら、null合体演算子を使う方法もあります。
C#var sortedPeople = people
.OrderBy(person => person.Name ?? "")
.ToList();
nullを含む可能性があるプロパティで並び替える場合は、nullをどう扱うかを意識しておきましょう。
7. OrderByでよくあるエラーとつまずきポイント
7-1. OrderByが使えないときの原因
OrderByが使えない場合、まず確認すべきなのはusing System.Linq;です。
C#using System.Linq;
これがないと、次のようなコードでOrderByが認識されないことがあります。
C#var sortedNumbers = numbers.OrderBy(x => x).ToList();
また、対象がIEnumerable<T>として扱えない型の場合も、OrderByをそのまま使えないことがあります。
通常のList<T>であれば問題なく使えます。
C#var numbers = new List<int> { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x).ToList();
Visual StudioなどでOrderByに赤い波線が出る場合は、まずSystem.Linqが読み込まれているか確認しましょう。
7-2. ToListを忘れてListとして扱えないケース
OrderByの戻り値はList<T>ではないため、List<T>として扱いたい場合はToList()が必要です。
次のコードはエラーになります。
C#List<int> sortedNumbers = numbers.OrderBy(x => x);
正しくは次のように書きます。
C#List<int> sortedNumbers = numbers.OrderBy(x => x).ToList();
ただし、foreachで回すだけならToList()がなくても動作します。
C#var sortedNumbers = numbers.OrderBy(x => x);
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
後続の処理でList<T>のメソッドを使いたい場合や、リストとして変数に保持したい場合は、ToList()を付けるとよいでしょう。
7-3. ラムダ式の書き方を間違えるケース
OrderByでは、並び替えの基準をラムダ式で指定します。
基本形は次のとおりです。
C#list.OrderBy(x => x)
オブジェクトのプロパティで並び替える場合は、次のように書きます。
C#users.OrderBy(user => user.Age)
よくある間違いとして、プロパティ名だけを書いてしまうケースがあります。
C#var sortedUsers = users.OrderBy(Age).ToList();
このような書き方は通常できません。
正しくは、各要素を表す変数をラムダ式で受け取り、そのプロパティを指定します。
C#var sortedUsers = users.OrderBy(user => user.Age).ToList();
user => user.Ageは、「userという1件のデータからAgeを取り出し、その値で並び替える」という意味です。
7-4. 文字列の並び順が想定と違うケース
文字列をOrderByで並び替えると、思った順番にならないことがあります。
特に、日本語、英字の大文字小文字、数字を含む文字列では注意が必要です。
C#var items = new List<string> { "item2", "item10", "item1" };
var sortedItems = items.OrderBy(item => item).ToList();
この場合、自然な数値順ではなく、文字列として比較されます。そのため、期待する順番と違う結果になることがあります。
また、大文字と小文字を区別した並び順になる場合もあります。
C#var names = new List<string> { "apple", "Banana", "cherry" };
var sortedNames = names.OrderBy(name => name).ToList();
大文字小文字を無視して並び替えたい場合は、次のように書くことがあります。
C#var sortedNames = names
.OrderBy(name => name.ToLower())
.ToList();
ただし、文字列比較を厳密に制御したい場合は、StringComparerなどの比較方法を使うことも検討します。
C#var sortedNames = names
.OrderBy(name => name, StringComparer.OrdinalIgnoreCase)
.ToList();
文字列の並び順が想定と違う場合は、「文字列として比較されている」「大文字小文字やカルチャの影響を受けることがある」という点を確認しましょう。
8. OrderByを使うときの注意点
8-1. 遅延実行に注意する
OrderByはLINQのメソッドであり、遅延実行されます。
遅延実行とは、OrderByを書いた時点ではすぐに並び替えが実行されず、実際に列挙されたタイミングで処理される仕組みです。
次の例を見てみましょう。
C#var numbers = new List<int> { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x);
numbers.Add(0);
foreach (var number in sortedNumbers)
{
Console.WriteLine(number);
}
実行結果は次のようになります。
C#0
1
2
3
sortedNumbersを作ったあとにnumbers.Add(0)していますが、foreachで実際に列挙した時点で並び替えが実行されるため、追加した0も結果に含まれます。
その時点の結果を確定させたい場合は、ToList()を使います。
C#var sortedNumbers = numbers.OrderBy(x => x).ToList();
ToList()を呼ぶと、その時点で並び替えが実行され、結果がリストとして固定されます。
8-2. 大量データを並び替えるときのパフォーマンス
OrderByは便利ですが、大量データを並び替える場合はパフォーマンスにも注意が必要です。
並び替え処理は、要素数が多くなるほど負荷が高くなります。
たとえば、数件や数百件程度のリストであればあまり問題になりませんが、数十万件、数百万件のデータを頻繁に並び替える場合は、処理時間やメモリ使用量を意識する必要があります。
特に、OrderBy(...).ToList()は、並び替えた結果を新しいリストとして作成します。そのため、元のリストとは別にメモリを使います。
C#var sortedItems = items.OrderBy(item => item.Price).ToList();
大量データを扱う場合は、次のような点を検討するとよいでしょう。
データベースから取得する場合はSQL側でORDER BYする、必要な件数だけ取得する、何度も同じ並び替えをしない、元のリストを直接並び替えてよい場合はList.Sortを使う、などです。
特にデータベースから取得した大量データをアプリケーション側で並び替えるより、データベース側で並び替えて必要な分だけ取得するほうが効率的なケースが多いです。
8-3. 元の順序を保持したい場合の考え方
OrderByは元のリストを変更しないため、元の順序を保持したい場合に便利です。
C#var originalUsers = new List<User>
{
new User { Name = "Tanaka", Age = 30 },
new User { Name = "Sato", Age = 20 },
new User { Name = "Suzuki", Age = 25 }
};
var sortedUsers = originalUsers.OrderBy(user => user.Age).ToList();
この場合、originalUsersは元の順番のまま残り、sortedUsersだけが年齢順になります。
元の順序が重要なデータでは、List.Sortで直接並び替えるより、OrderByで別のリストを作るほうが安全です。
また、並び替え後に元の順序へ戻したい可能性がある場合は、元のインデックスを保持しておく方法もあります。
C#var indexedUsers = users
.Select((user, index) => new { User = user, OriginalIndex = index })
.ToList();
このように元の位置を記録しておけば、あとから元の順番に戻すこともできます。
C#var restoredUsers = indexedUsers
.OrderBy(x => x.OriginalIndex)
.Select(x => x.User)
.ToList();
元の順序を保持したい場合は、OrderByで新しいリストを作るのが基本です。
8-4. 独自ルールで並び替えたい場合のComparer活用
通常のOrderByでは、数値や文字列などの標準的な比較ルールで並び替えます。
しかし、独自のルールで並び替えたい場合は、比較方法を指定できます。
たとえば、文字列を大文字小文字を無視して並び替えたい場合は、StringComparer.OrdinalIgnoreCaseを使えます。
C#var names = new List<string> { "apple", "Banana", "cherry" };
var sortedNames = names
.OrderBy(name => name, StringComparer.OrdinalIgnoreCase)
.ToList();
また、独自のIComparer<T>を作ることもできます。
次の例では、文字列の長さで並び替えます。
C#public class StringLengthComparer : IComparer<string>
{
public int Compare(string? x, string? y)
{
return (x?.Length ?? 0).CompareTo(y?.Length ?? 0);
}
}
C#var words = new List<string> { "apple", "cat", "banana", "dog" };
var sortedWords = words
.OrderBy(word => word, new StringLengthComparer())
.ToList();
ただし、文字列の長さで並び替えるだけなら、次のように書いたほうが簡単です。
C#var sortedWords = words.OrderBy(word => word.Length).ToList();
Comparerを使うのは、単純なプロパティ指定では表現しにくい独自ルールがある場合に向いています。
9. C# ListのOrderByに関するよくある質問
9-1. OrderByとSortはどちらを使うべきか
元のリストを変更したくない場合はOrderByを使うのがおすすめです。
C#var sortedNumbers = numbers.OrderBy(x => x).ToList();
この場合、元のnumbersは変更されません。
一方、元のリスト自体を並び替えてよい場合は、List.Sortを使えます。
C#numbers.Sort();
オブジェクトのリストをわかりやすく並び替えたい場合は、OrderByのほうが読みやすいことが多いです。
C#var sortedUsers = users.OrderBy(user => user.Age).ToList();
その場で並び替えたい場合や、新しいリストを作りたくない場合は、Sortが向いています。
C#users.Sort((a, b) => a.Age.CompareTo(b.Age));
迷った場合は、元のリストを残したいならOrderBy、直接変更してよいならSortと考えるとわかりやすいです。
9-2. OrderByで元のListを直接変更できるのか
OrderBy自体は、元のListを直接変更しません。
C#var numbers = new List<int> { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x).ToList();
このコードでは、numbersは元の順番のままで、sortedNumbersに並び替え後の結果が入ります。
元の変数を並び替え後のリストで上書きしたい場合は、次のように再代入します。
C#numbers = numbers.OrderBy(x => x).ToList();
ただし、この場合も元のListインスタンスを直接並び替えているわけではありません。新しく作った並び替え済みリストを、同じ変数に代入しているだけです。
元のリストそのものを直接並び替えたい場合は、List.Sortを使います。
C#numbers.Sort();
9-3. 降順と昇順を組み合わせて並び替えられるのか
できます。
降順と昇順を組み合わせたい場合は、OrderBy、OrderByDescending、ThenBy、ThenByDescendingを組み合わせます。
たとえば、スコアが高い順に並び替え、同じスコアの場合は名前順にする場合は次のように書きます。
C#var sortedUsers = users
.OrderByDescending(user => user.Score)
.ThenBy(user => user.Name)
.ToList();
部署名を昇順にし、同じ部署の中では年齢が高い順にする場合は次のように書けます。
C#var sortedUsers = users
.OrderBy(user => user.Department)
.ThenByDescending(user => user.Age)
.ToList();
最初の条件にはOrderByまたはOrderByDescendingを使い、2番目以降の条件にはThenByまたはThenByDescendingを使うのがポイントです。
9-4. Dictionaryや配列にもOrderByは使えるのか
OrderByはList<T>だけでなく、配列やDictionaryなど、LINQで扱えるコレクションにも使えます。
配列を並び替える例です。
C#int[] numbers = { 3, 1, 2 };
var sortedNumbers = numbers.OrderBy(x => x).ToArray();
配列として結果を受け取りたい場合は、ToArray()を使います。
C#int[] sortedNumbers = numbers.OrderBy(x => x).ToArray();
DictionaryにもOrderByを使えます。
キーで並び替える場合は次のように書きます。
C#var dictionary = new Dictionary<string, int>
{
{ "Orange", 300 },
{ "Apple", 100 },
{ "Banana", 200 }
};
var sortedByKey = dictionary.OrderBy(pair => pair.Key);
foreach (var item in sortedByKey)
{
Console.WriteLine($"{item.Key}: {item.Value}");
}
値で並び替える場合は、Valueを指定します。
C#var sortedByValue = dictionary.OrderBy(pair => pair.Value);
結果をDictionaryに戻したい場合は、ToDictionaryを使います。
C#var sortedDictionary = dictionary
.OrderBy(pair => pair.Value)
.ToDictionary(pair => pair.Key, pair => pair.Value);
ただし、Dictionaryは本来、順序付きのコレクションとして使うものではありません。並び順が重要な場合は、並び替えた結果をリストとして扱うほうがわかりやすいこともあります。
まとめ
C#でListを並び替える場合、LINQのOrderByを使うと簡潔に書けます。
昇順に並び替える場合はOrderBy、降順に並び替える場合はOrderByDescendingを使います。
C#var ascending = numbers.OrderBy(x => x).ToList();
var descending = numbers.OrderByDescending(x => x).ToList();
オブジェクトのリストでは、並び替えたいプロパティをラムダ式で指定します。
C#var sortedUsers = users.OrderBy(user => user.Age).ToList();
複数条件で並び替える場合は、OrderByを何度も書くのではなく、ThenByやThenByDescendingを使います。
C#var sortedUsers = users
.OrderBy(user => user.Age)
.ThenBy(user => user.Name)
.ToList();
また、OrderByは元のListを直接変更しません。並び替えた結果をList<T>として使いたい場合は、ToList()を付ける必要があります。
C#var sortedList = originalList.OrderBy(x => x).ToList();
元のリスト自体を直接並び替えたい場合は、List.Sortを使う方法もあります。
C#numbers.Sort();
OrderByは、元のデータを保持したまま並び替え結果を作りたいときに便利です。一方で、元のリストをその場で変更してよい場合はSortも選択肢になります。
C#でListを並び替えるときは、昇順・降順・複数条件・元のリストを変更するかどうかを意識して、OrderBy、OrderByDescending、ThenBy、ThenByDescending、List.Sortを使い分けましょう。

