【C#】LINQのToDictionaryメソッド:リストや配列をDictionaryに変換して検索を効率化する方法

目次

リストを「検索しやすい形」に変換する

C#でデータを扱う際、データベースやAPIから取得したデータは、多くの場合List<T>や配列として提供されます。これをそのまま「IDを使って特定のデータを検索」しようとすると、リストの先頭から順に探す(線形探索)必要があり、データ量が増えると処理速度が低下します。

特定のキー(IDなど)に基づいて頻繁にデータへアクセスする場合は、リストを**Dictionary<TKey, TValue>(辞書)**に変換するのが定石です。辞書に変換することで、データの検索速度はO(1)(ほぼ一瞬)になります。

LINQのToDictionaryメソッドを使用すると、コレクションからキーと値を抽出して、簡単にDictionaryを作成できます。

この記事では、ToDictionaryの2つの主要な使い方と、使用時に発生しやすい例外への対策について解説します。


1. キーのみを指定して変換する

ToDictionaryの最も基本的な使い方は、「どのプロパティを辞書のキーにするか」だけを指定する方法です。この場合、値(Value)にはオブジェクトそのものが格納されます。

  • 戻り値の型: Dictionary<キーの型, オブジェクトの型>

コード例:IDをキーにして辞書化

都道府県コード(ID)を持つクラスのリストを、IDで検索できる辞書に変換する例です。

using System;
using System.Collections.Generic;
using System.Linq;

// 都道府県データを表すレコード
public record Prefecture(int Id, string Name, string Region);

public class ToDictionaryBasicExample
{
    public static void Main()
    {
        // データソース(配列)
        var prefectureList = new[]
        {
            new Prefecture(1, "Hokkaido", "Hokkaido"),
            new Prefecture(13, "Tokyo", "Kanto"),
            new Prefecture(23, "Aichi", "Chubu"),
            new Prefecture(27, "Osaka", "Kansai"),
            new Prefecture(40, "Fukuoka", "Kyushu")
        };

        // ID をキーにして Dictionary に変換
        // キー: int (Id), 値: Prefecture (オブジェクト自体)
        Dictionary<int, Prefecture> prefectureDict = 
            prefectureList.ToDictionary(p => p.Id);

        Console.WriteLine("--- 辞書変換後のアクセス ---");

        // IDを指定して高速にアクセス可能
        int searchId = 13;
        if (prefectureDict.TryGetValue(searchId, out var pref))
        {
            Console.WriteLine($"ID: {searchId} => {pref.Name} ({pref.Region})");
        }

        // 辞書の中身を表示
        Console.WriteLine("\n--- 全データ ---");
        foreach (KeyValuePair<int, Prefecture> item in prefectureDict)
        {
            Console.WriteLine($"Key: {item.Key}, Value: {item.Value.Name}");
        }
    }
}

出力結果:

--- 辞書変換後のアクセス ---
ID: 13 => Tokyo (Kanto)

--- 全データ ---
Key: 1, Value: Hokkaido
Key: 13, Value: Tokyo
Key: 23, Value: Aichi
Key: 27, Value: Osaka
Key: 40, Value: Fukuoka

2. キーと値の両方を指定して変換する

キーだけでなく、「値として何を格納するか」も指定したい場合があります。オブジェクト全体ではなく、特定のプロパティ(例:名前だけ)を値として保持したい場合に使用します。

  • 戻り値の型: Dictionary<キーの型, 指定した値の型>

コード例:IDをキー、名前を値にする

先ほどのデータから、「ID」と「都道府県名」だけのペアを持つ辞書を作成します。

using System;
using System.Collections.Generic;
using System.Linq;

public class ToDictionaryValueSelectorExample
{
    public static void Main()
    {
        var prefectureList = new[]
        {
            new { Id = 1, Name = "Hokkaido", Code = "HKD" },
            new { Id = 13, Name = "Tokyo", Code = "TKY" },
            new { Id = 27, Name = "Osaka", Code = "OSK" }
        };

        // 第1引数: キーの選択 (Code)
        // 第2引数: 値の選択 (Name)
        Dictionary<string, string> codeToNameMap = 
            prefectureList.ToDictionary(x => x.Code, x => x.Name);

        Console.WriteLine("--- コード検索マップ ---");
        foreach (var pair in codeToNameMap)
        {
            Console.WriteLine($"{pair.Key} -> {pair.Value}");
        }
    }
}

出力結果:

--- コード検索マップ ---
HKD -> Hokkaido
TKY -> Tokyo
OSK -> Osaka

重要な注意点:キーの重複は例外発生

ToDictionaryを使用する上で最も注意すべき点は、キーとして指定した値が重複していた場合、ArgumentException が発生して処理が停止することです。Dictionaryは一意なキーしか持てないためです。

もしデータソースに重複が含まれる可能性がある場合は、事前に重複を除去するか、ToLookupメソッド(キーに対して複数の値を持てる)の使用を検討する必要があります。

重複回避のアプローチ

var duplicateData = new[]
{
    new { Id = 1, Name = "A" },
    new { Id = 1, Name = "B" } // IDが重複
};

// そのまま ToDictionary すると例外発生
// var dict = duplicateData.ToDictionary(x => x.Id); // ArgumentException!

// 対策: GroupBy などで重複を排除してから辞書化する
// 例: 重複した場合は「最後のデータ」を採用する
var safeDict = duplicateData
    .GroupBy(x => x.Id)
    .ToDictionary(g => g.Key, g => g.Last());

Console.WriteLine(safeDict[1].Name); // "B"

まとめ

ToDictionaryは、シーケンスを「検索に最適化された形式」に変換する強力なメソッドです。

  • ToDictionary(x => x.Key): キーを指定し、要素そのものを値とする辞書を作成します。
  • ToDictionary(x => x.Key, x => x.Value): キーと、抽出した値を格納する辞書を作成します。
  • 注意: キーの重複は許されません。データの一意性が保証されていない場合は、事前の重複排除処理が必要です。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次