C#のDictionaryをソートする3つの方法

C#でDictionaryの内容をソートする方法を3つ紹介したいと思います。

前提条件

説明に使用するデータ構造は下の通りです。

// 必要な宣言
using System.Collections.Generic;
using System.Linq;

// 値に使用するクラス
  public class Item
  {
      // プロパティ
      public int ID { get; set; }
      public string No { get; set; }
      // メソッド
      public override string ToString() { return $"ID = {this.ID}, No = {this.No}"; }
  }

// 説明に使用するDictionary
var itemTable = new Dictionary<int, Item>()
{
    { 0, new Item() { ID = 0, No = "0" } },
    { 3, new Item() { ID = 3, No = "3" } },
    { 2, new Item() { ID = 2, No = "2" } },
    { 1, new Item() { ID = 1, No = "1" } },
};

その1:SortedDictionaryを利用する

Dictionaryに要素を追加した時点で整列済みとなるSortedDictionaryを使用する方法です。DictionaryとSortedDictionaryは両方ともIDictionaryを継承しているのでIDictionaryで操作できます。

先ずはインスタンスを作成する時にSortedDictionaryを宣言します。

引数なしのコンストラクタでインスタンス化するとTKeyに対しデフォルトの整列規則(文字コード順)が適用されます。

// 宣言:SortedDictionaryとしてインスタンスを作成
var itemTable = new SortedDictionary<int, Item>();

この状態で冒頭のテーブルの内容を foreach で列挙すると内容が整列されています。

//public static void DisplayItems_1(SortedDictionary<int, Item> itemTable)
public static void DisplayItems_1(IDictionary<int, Item> itemTable)
{
    foreach (KeyValuePair<int, Item> item in itemTable)
    {
        Console.WriteLine($"{item.Key} = ,{item.Value.ToString()}");
    }
}
// 出力内容:デフォルトはKeyの昇順に整列される
// 0 = ,ID = 0, No = 0
// 1 = ,ID = 1, No = 1
// 2 = ,ID = 2, No = 2
// 3 = ,ID = 3, No = 3

次はコンストラクタに自作の整列規則として IComparer を与える場合です。

IComparer は interface のため、先ずは継承して自作のクラスを作成します。

// 自作の整列規則クラス
public sealed class SortRule : IComparer<int> // <>の中身はKeyの型を指定する
{
    // IComparerの実装
    public int Compare(int x, int y)
    {
        return y - x;
    }
}

次にSortedDictionaryのコンストラクタに上記クラスを指定します。

var itemTable = new SortedDictionary<int, Item>(new SortRule())

上記のDictionaryをforeachで列挙すると以下の通り逆順になります。

public static void DisplayItems_1(SortedDictionary<int, Item> itemTable)
{
    foreach (KeyValuePair<int, Item> item in itemTable)
    {
        Console.WriteLine($"{item.Key} = ,{item.Value.ToString()}");
    }
}
// 出力内容:逆順になっている
// 3 = ,ID = 3, No = 3
// 2 = ,ID = 2, No = 2
// 1 = ,ID = 1, No = 1
// 0 = ,ID = 0, No = 0

その2:拡張メソッドを利用する

System.Linqに定義されている拡張メソッドを利用する方法です。

昇順はOrderByメソッドを使用し、降順はOrderByDescendingメソッドを使用します。

using System.Linq; // ある事を確認する

public static void DisplayItems_1(IDictionary<int, Item> itemTable)
{
    // キーで昇順
    IOrderedEnumerable<KeyValuePair<int, Item>> _table_1 =
        itemTable.OrderBy(selector =>
        {
            return selector.Key;
        });

    // キーで降順
    IOrderedEnumerable<KeyValuePair<int, Item>> _table_2 =
        itemTable.OrderByDescending(selector =>
        {
            return selector.Key;
        });
}

その3:リストにしてからソートする

一旦リストにしてから整列する方法です。あまり使うときないかも?

// キーと値両方をリスト化
List<KeyValuePair<int, Item>> keyValueList = itemTable.ToList();
keyValueList.Sort(); // Sortメソッドのデフォルトで整列

// キーをリスト化
List<int> keyList = itemTable.Keys.ToList();
keyList.Sort();

// 値をリスト化
List<Item> valueList = itemTable.Values.ToList();
valueList.Sort();

List.Sortには整列規則をデリゲート(Comparison)で指定できるので必要に応じて整列規則を指定します。

関係する記事

以下基本的な使い方の紹介です。

takachan.hatenablog.com