【LINQ】C#でソートしたいならOrderByを覚えておけばOK

C#

こんにちは、働く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を使うことができます。

さんさめ
さんさめ

逆順にしたい時は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をコードから消す
で詳しく解説しています。

コメント

タイトルとURLをコピーしました