Enumerable.​OrderBy メソッド / List<T>.OrderBy メソッドを利用する IEnumerableインターフェイスを持つオブジェクトをソートする - C#

Enumerable.​OrderBy メソッドを利用して、Enumerable オブジェクトの要素の順番を並び替えるコードを紹介します。

概要

Listなど、一つのオブジェクトに複数の値が格納される Collection型のオブジェクトで条件に従って要素の順番を並び替えたいことがあります。オーソドックスな方法としては、forループやforeachループを利用してソートする方法や、ListのSortメソッドを利用する方法があります。通常はこれらの処理を利用すれば問題ありませんが、適用させる処理のロジックを使いまわす場合や、よりコードをシンプルに記述したいこともあります。
Enumerable オブジェクトの OrderBy メソッドを利用することでループ処理を無くしたシンプルなコードを記述できます。

プログラム例

今回は IEnumerable インターフェイスを実装しているListクラスを利用してOrderBy メソッドを利用するサンプルを紹介します。

UI

下図のUIを作成します。複数行のテキストボックスにボタンを5つ配置します。

コード

下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace OrderByDemo
{
  public partial class FormListOrderBy : Form
  {
    public FormListOrderBy()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      Func<string, int> ProcFunc = orderby_proc;
      IEnumerable<string> strenum = StrList.OrderBy(ProcFunc);

      List<string> ProcList = strenum.ToList<string>();

      foreach (string t in ProcList) {
        textBox1.Text += t + "\r\n";
      }
    }

    private int orderby_proc(string value)
    {
      return value.Length;
    }

    private void button2_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = StrList.OrderBy(delegate (string value) {
        return value.Length;
      });
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

    private void button3_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = StrList.OrderBy((string value) => {
        return value.Length;
      });
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

    private void button4_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = StrList.OrderBy((value) => value.Length);
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

    private void button5_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = from value in StrList orderby value.Length select value;
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }
  }
}

実行結果と解説

上記のプロジェクトを実行します。下図のウィンドウが表示されます。

button1

[button1]をクリックすると下記のコードが実行されます。
先頭部分はListオブジェクトを作成しリストに文字列の値を追加するコードです。値の追加後に、OrderBy() メソッドを呼び出します。OrderBy メソッドの引数には、orderby_procメソッドを与えます。orderby_procメソッドは Func(string,int) 型のメソッドであり、戻り値にintを返すメソッドです。StrListの各要素に対して、orderby_proc()メソッドが呼び出されます。要素の値は、orderby_proc メソッドの第一引数 value に与えられます。orderby_proc メソッドの戻り値の値に応じて順番が決定されます。値が大きいほど要素の後ろの順番になります。
今回のorderby_proc()メソッドのコードは要素の値の文字列の長さを利用しています。値の文字列が短いものから順番に並べられる動作になります。
結果はOrderByメソッドの戻り値として返ります。処理後に foreachループで結果のリストに含まれる要素の値をテキストボックスに表示します。
    private void button1_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      Func<string, int> ProcFunc = orderby_proc;
      IEnumerable<string> strenum = StrList.OrderBy(ProcFunc);

      List<string> ProcList = strenum.ToList<string>();

      foreach (string t in ProcList) {
        textBox1.Text += t + "\r\n";
      }
    }

    private int orderby_proc(string value)
    {
      return value.Length;
    }

[button1]をクリックします。テキストボックスに、「あひサブ」「ぺんぎんクッキー」「らくだ黒キャラメル」「しろくまアイスクリーム」「くじらデラックスショートケーキ」の順番で文字列が表示されます。文字列の短い順番にソートされていることが確認できます。

button2

[button2]クリック時には下記のコードが実行されます。[button1]のコードとの違いは、button1ではOrderByメソッドの引数にorderby_proc() メソッドを与えましたが、button2ではメソッドを与えずに、OrderByメソッドの引数に匿名メソッドを記述しています。匿名メソッドを利用すると、メソッドの実装を別のメソッドに分けた記述が不要になります。
    private void button2_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = StrList.OrderBy(delegate (string value) {
        return value.Length;
      });
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

[button2]をクリックします。テキストボックスに、「あひサブ」「ぺんぎんクッキー」「らくだ黒キャラメル」「しろくまアイスクリーム」「くじらデラックスショートケーキ」の順番で文字列が表示されます。文字列の短い順番にソートされていることが確認できます。

button3

[button3]のコードは下記になります。button2のコードでは、OrderBy() メソッドに匿名メソッドを与えていましたが、ラムダ式での記述に書き換えています。
    private void button3_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = StrList.OrderBy((string value) => {
        return value.Length;
      });
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

プログラムを実行し[button3]をクリックします。テキストボックスにbutton2クリック時と同様の文字列が表示されます。

button4

[button4]がクリックされると下記のコードが実行されます。button3のコードのラムダ式はステートメント形式のラムダ式でしたが、これを式形式のラムダ式に書き換えています。
    private void button4_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = StrList.OrderBy((value) => value.Length);
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

プログラムを実行し[button4]をクリックします。[button1]~[button4]まで同じ処理であることがわかります。

button5

[button5]をクリックした際に実行されるコードは下記になります。このコードは、OrderByメソッドの呼び出しをメソッドの呼び出し形式で記述する方式からLINQの記述に変更したコードになります。orderby 節の後ろに記述したラムダ式が抽出条件の式となります。また、結果となる変数をselect節で指定しています。LINQについてはこちらの記事を参照してください。
    private void button5_Click(object sender, EventArgs e)
    {
      List<string> StrList = new List<string>();
      StrList.Add("ぺんぎんクッキー");
      StrList.Add("らくだ黒キャラメル");
      StrList.Add("しろくまアイスクリーム");
      StrList.Add("あひサブ");
      StrList.Add("くじらデラックスショートケーキ");

      IEnumerable<string> tempenum = from value in StrList orderby value.Length select value;
      List<string> ResultList = tempenum.ToList();

      foreach (string s in ResultList) {
        textBox1.Text += s + "\r\n";
      }
    }

プログラムを実行し[button5]をクリックします。[button1]~[button5]まで同じ処理であることがわかります。


OrderByメソッドを利用したソートが実装できました。

補足:逆順でのソート

OrderByメソッドの順番とは逆順にソートする場合は、OrderByDescending() メソッドが利用できます。OrderByメソッドのソート順とは逆の順番でソートできます。
  private void button4_Click(object sender, EventArgs e)
  {
    List<string> StrList = new List<string>();
    StrList.Add("ぺんぎんクッキー");
    StrList.Add("らくだ黒キャラメル");
    StrList.Add("しろくまアイスクリーム");
    StrList.Add("あひサブ");
    StrList.Add("くじらデラックスショートケーキ");

    IEnumerable<string> tempenum = StrList.OrderByDescending((value) => value.Length);
    List<string> ResultList = tempenum.ToList();

    foreach (string s in ResultList) {
      textBox1.Text += s + "\r\n";
    }
  }

LINQでの記述ではソートの順番を逆にする場合は descending キーワードが利用できます。descending を記述すると、ソート順を逆にできます。(正順の場合は ascending キーワードですが通常は省略します。)
  private void button5_Click(object sender, EventArgs e)
  {
    List<string> StrList = new List<string>();
    StrList.Add("ぺんぎんクッキー");
    StrList.Add("らくだ黒キャラメル");
    StrList.Add("しろくまアイスクリーム");
    StrList.Add("あひサブ");
    StrList.Add("くじらデラックスショートケーキ");

    IEnumerable<string> tempenum = from value in StrList orderby value.Length descending select value;
    List<string> ResultList = tempenum.ToList();

    foreach (string s in ResultList) {
      textBox1.Text += s + "\r\n";
    }
  }

上記のコードに変更したプログラムを実行し、[button5]をクリックします。下図の結果が表示されます。ソート順が逆になっていることが確認できます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2018-09-17
iPentec all rights reserverd.