こんにちは、働くC#プログラマーのさんさめです。
リストをソートしたい時、
どんなメソッドを使えばよいのか、
パッと思い出せるでしょうか?
言語によっても個性がでる上に、
ソートアルゴリズムまで違ったりするので、
なかなか頭に入ってこないですよね。
また、ひとくちにリストと言っても、
型によっては、標準では
ソート関数を持っていなかったりするので、
厄介な側面があります。
C#でソートしたい場合は、
LINQ拡張メソッドのOrderBy
を覚えておけば9割大丈夫です。
OrderByでリストを昇順に並び替えられる
OrderByは、
渡されたリストを昇順に並び替えるメソッドです。
ただし、
引数無しで勝手にソートしてくれるわけではなく、
「何をキーにして並び替えるのか」
を指定する必要があります。
以下はサンプルコードです。
var list = new[] { "b", "a", "d", "c" };
// 自明に見えても、
// 以下のように自身をキーに指定する必要がある
var orderedList = list.OrderBy(x => x);
foreach (var item in orderedList)
{
Console.WriteLine(item);
}
「stringの配列」のような、
明らかにキーが不要そうな場面でも、
OrderBy(x => x)
という単に自身を返すラムダを渡すことで
キーを指定する必要があります。

なんか面倒くさっ

たしかにね…でも、独自クラスの時は、
これが使いやすいのよ
組み込み型の配列では、
使いづらい面に感じますが、
逆に言えば、
どんなクラスであっても、
任意のプロパティを指定して
簡単に並び替えができるということでもあります。

ラムダ式でパッと渡せるので、
クラス側に比較用インタフェースの実装を
行ったりしなくてよい、
というメリットがあります。
さらに、OrderByは
IEnumerable<T>を実装しているクラスなら、
なんにでも適用可能であるため、
非常に汎用性が高いです。
たとえば、辞書の要素を、
キーが昇順になるように列挙したい、
といったケースがあったとしましょう。
(デバッグ時にやりたくなります)
DictionaryはIEnumerable<T>であるため、
OrderByを使うことができます。


この便利さ…
Distinctも見習ってほしい
逆順にしたい時はOrderByDescendingを使う
昇順ではなく、降順にしたいケースもあると思います。
専用に、OrderByDescendingがあるので、
こちらを使えばOKです。

OrderByとReverseを組み合わせても良いですが…
OrderByDescendingの方が素直ですね。
ソート結果はToArrayでキャッシュしておくと安心
少し細かいのですが、
OrderByはWhereなどと同じく、
遅延実行(※)で動作します。
(※メソッドを呼んだ瞬間には処理が回らない)
つまり、以下のような書き方をすると、
無駄にソート処理を2回行ってしまいます。
var list = new[] { "b", "a", "d", "c" };
var orderdList = list.OrderBy(x => x);
foreach (var item in orderdList)
{
Console.WriteLine(item);
}
// ↓ソート処理からやり直し
foreach (var item in orderdList)
{
Console.WriteLine(item);
}
要素数が少ないリストの時は
あまり気にする必要はありませんが…。
数万オーダーのリストをソートして、
かつ複数個所で利用したい場合は、
OrderByの直後にToArrayを呼んで、
あらかじめ配列化しておくと良いでしょう。
ToArrayによるキャッシュ化は、
LINQの遅延実行の分かりにくさを
打ち消してくれるので、
頭の片隅に覚えておくことをおススメします。
まとめ
まとめです。
- OrderByはC#で並び替えを行いたい時に、
覚えておくべき必携のメソッド - ラムダ式でキーを渡すことで、
どんなクラスでも簡単に並び替えが可能 - OrderByは遅延実行であることに注意
- 笑えないレベルで遅くなることも
最後までお読みいただき、ありがとうございました。
関連記事
OrderByでは、ラムダ式を渡すことで
簡単に任意のクラスのソートができましたが、
Distinct(重複除去)では、
代替手段が存在しません。
【LINQ】任意のクラスでDistinctを使う方法
で詳しく解説しています。
LINQに慣れない方は、
Whereから使っていくと良いでしょう。
【LINQ】Whereを使ってガード節continueをコードから消す
で詳しく解説しています。
コメント