連載:[完全版]究極のC#プログラミング

Chapter15 LINQとクエリ式

川俣 晶
2010/03/17
Page 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

15.21 let句

 クエリ式には、もう1つだけ紹介する価値のある句がある。それが「let句」である。

 このlet句は、クエリ式の途中で値を範囲変数に保存する機能を持つのだが、クエリ式を書いてみても効能がわかりにくい。なくてもクエリ式は書けてしまうのである。実は筆者も存在意義がわかっていなかったが、本稿を書くに当たって調べたところ、非常に重要な機能があることがわかった。

 以下、let句を使わない例(リスト15.26)と、使った例(次ページリスト15.27)の差を見ていただきたい。注目点は、クエリ式から呼び出している変換メソッドの呼び出し回数である。

using System;
using System.Linq;

class Program
{
  private static int count = 0;

  private static int conversion(int n)
  {
    count++;
    return n; // 何か有意義な変換を行っていると想定する
  }

  static void Main(string[] args)
  {
    int[] a = { 1, 2, 3 };
    int[] b = { 4, 5, 6 };

    var q = from n in a
            from m in b
            select conversion(n) + m;

    foreach (var n in q)
    {
      Console.WriteLine(n);
    }
    // 出力: 5 6 7 6 7 8 7 8 9

    Console.WriteLine("conversion called: {0}", count);
    // 出力:conversion called: 9
  }
}
リスト15.26 変換メソッドを呼び出すクエリ式

 let句を使う場合は、次のリスト15.27のようにクエリ式を書き換える。

var q = from n in a
        let cn = conversion(n)
        from m in b
        select cn + m;
リスト15.27 let句を使ったクエリ式

5 6 7 6 7 8 7 8 9 conversion called: 3
リスト15.27のクエリ式の場合の実行結果

 さて、見てのとおり変換メソッドが呼び出される回数が9回から3回に激減した。減少量は、扱うデータ量(2番目のfrom句の列挙数)が増えればさらに差が大きくなるだろう。

 このような差が出る理由は、次のとおりである。

  • リスト15.26の第1のfrom句は3回、第2のfrom句も3回の列挙を持つため、select句は3×3=9回繰り返される
  • したがって、リスト15.26ではselect句に書かれたメソッド呼び出しも9回発生する
  • リスト15.27の第2のfrom句より手前の世界では、第1のfrom句だけが効力を持つ。この世界では、3回だけ列挙が発生する
  • リスト15.27の第2のfrom句より手前に書かれたlet句は3回だけ実行される。つまり、メソッド呼び出しは3回しか発生しない

 つまり、まとめると、1つのクエリ式内で、列挙回数が増えるタイミングよりも手前に時間のかかる処理を行うと、それだけ大きな高速化を達成できるわけである。let句は式を計算して範囲変数に代入する効能しか持たないが、それを使えば計算を行うタイミングを前倒しし、このような高速化を達成することができるわけである。


 INDEX
  [完全版]究極のC#プログラミング
  Chapter15 LINQとクエリ式
    1.15.1 LINQの面白さ
    2.15.2 LINQとは何か?
    3.15.3 「値の集まり」に対する演算
    4.15.4 なぜLINQなのか?
    5.15.5 最も基本的なLINQ
    6.15.6 LINQの本質は列挙
    7.15.7 LINQを使ううえでの注意点
    8.15.8 クエリ結果を加工する
    9.15.9 複数のソースからクエリする
    10.15.10 条件で絞り込む
    11.15.11 一部項目のみselectする
    12.15.12 シンプルなソート
    13.15.13 クエリの接続
    14.15.14 クエリ結果のグループ化
    15.15.15 複数ソースを関連付けるjoin句
    16.15.16 from句とjoin句のパフォーマンス
    17.15.17 join句のグループ化結合
    18.15.18 join句の左外部結合
    19.15.19 単独で使うDefaultIfEmptyメソッド
    20.15.20 内部列挙を伴うfrom句の二重使用
  21.15.21 let句
    22.15.22 クエリのインスタンス化
    23.15.23 クエリ結果の個数を得る
    24.15.24 Anyメソッドと存在チェック/【C#olumn】クエリ式のデバッグテクニック
    25.15.25 まとめ/【C#olumn】LINQの難しさ/【Exercise】練習問題
 
インデックス・ページヘ  「[完全版]究極のC#プログラミング」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間