【C#】LINQのToLookupメソッドで要素をキー別にグループ化・検索する

データの集合を特定の条件(キー)ごとにグループ化したい場合、LINQのToLookupメソッドを使用すると非常に便利です。

よく似た機能にGroupByがありますが、ToLookupは即時実行され、扱いやすいILookup<TKey, TElement>インターフェースを返すという特徴があります。今回は、社内の従業員リストを部署ごとにグループ化するシナリオを通じて、ToLookupの基本的な使い方と特性について解説します。


目次

ToLookupメソッドの概要

ToLookupメソッドは、シーケンス(配列やリストなど)の各要素に対してキーを選択し、そのキーに基づいて要素をグループ化したILookup<TKey, TElement>を作成します。

一般的なDictionary<TKey, TValue>が一つのキーに対して一つの値を持つのに対し、ILookup一つのキーに対して複数の値(コレクション)を持つことができます。これは「1対多」の関係を表現するのに最適です。

実践的なコード例:部署ごとの従業員リスト作成

以下のコードは、従業員データ(名前と部署名)のリストから、部署をキーとして従業員名のリストを引けるルックアップテーブルを作成する例です。

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

namespace EmployeeManagement
{
    // 従業員を表すレコード
    public record Employee(string Name, string Department);

    class Program
    {
        static void Main()
        {
            // 従業員データのリスト
            var employees = new[]
            {
                new Employee("佐藤", "Sales"),
                new Employee("田中", "Engineering"),
                new Employee("鈴木", "Sales"),
                new Employee("高橋", "Engineering"),
                new Employee("伊藤", "Human Resources"),
                new Employee("渡辺", "Sales")
            };

            // 1. ToLookupを使用してグループ化
            // 第1引数: グループ化のキー(部署)
            // 第2引数: 値として格納する要素(名前)
            ILookup<string, string> employeesByDept = 
                employees.ToLookup(e => e.Department, e => e.Name);

            // 2. グループごとのデータを出力
            foreach (IGrouping<string, string> group in employeesByDept)
            {
                Console.WriteLine($"# 部署: {group.Key}");
                
                foreach (var name in group)
                {
                    Console.WriteLine($"  - {name}");
                }
            }

            // 3. 特定のキー(部署)を指定して直接アクセスすることも可能
            Console.WriteLine("\n--- Engineering部のメンバー ---");
            foreach (var engineer in employeesByDept["Engineering"])
            {
                Console.WriteLine($"  - {engineer}");
            }
        }
    }
}

実行結果

Plaintext

# 部署: Sales
  - 佐藤
  - 鈴木
  - 渡辺
# 部署: Engineering
  - 田中
  - 高橋
# 部署: Human Resources
  - 伊藤

--- Engineering部のメンバー ---
  - 田中
  - 高橋

技術的なポイントとGroupByとの違い

1. キーセレクタと要素セレクタ

ToLookupのオーバーロードでは、第1引数に「何をキーにするか(KeySelector)」、第2引数に「値を何にするか(ElementSelector)」を指定できます。上記の例では、e => e.Nameを指定しているため、ルックアップの値はEmployeeオブジェクトそのものではなく、string型の名前になります。これにより、必要なデータだけを抽出した軽量な構造を作成できます。

2. 存在しないキーへのアクセス安全性

Dictionaryの場合、存在しないキーにインデクサでアクセスすると例外が発生しますが、ILookupの場合は空のシーケンスを返します。そのため、事前にキーの存在確認(ContainsKeyなど)を行う必要がなく、コードをシンプルに記述できます。

3. 即時実行と遅延実行

これがGroupByとの最大の違いです。

  • GroupBy: 遅延実行(Lazy Evaluation)されます。列挙(foreachなど)するまで処理は行われません。
  • ToLookup: 即時実行(Immediate Execution)されます。メソッドが呼ばれた時点で全てのデータを読み込み、メモリ上にデータ構造を構築します。

データソースがデータベースや外部APIである場合や、結果をキャッシュとして繰り返し利用したい場合は、ToLookupを使用してデータをメモリ上に確定させるアプローチが有効です。

まとめ

ToLookupを使用すると、フラットなリストデータを簡単に階層構造(キーと値のコレクション)に変換できます。「キーが存在しない場合でもエラーにならず空の結果を返す」という特性は、検索ロジックを実装する際に非常に扱いやすいものです。データの集計や分類が必要な場面で、ぜひ活用してみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

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

目次