特集:Road to LINQ

C#で解説する「データ処理の直交化と汎用化」

岩永 信之
2011/06/14
Page1 Page2 Page3

 本稿では、LINQ(Language Integrated Query)の生い立ちについての話をしてみたい。

 LINQは、C# 3.0の目玉機能として、2005年夏に発表、2008年に初頭に製品化されたものである。製品化から数えてももう3年が過ぎたわけだが、いまだ誤解の多い機能だろう。LINQの一側面だけを見て、

  • O/Rマッパーの一種
  • C#やVB(Visual Basic)のコード中にSQL風のクエリを埋め込める機能

などといわれることもある。これは、一側面が見えているだけいいかもしれない。まれに、

  • if文やfor文が書ければ、プログラムは書ける
  • C# 3.0/VB 9で何だかいきなり機能が増えすぎてもう付いていけない

というような声さえ聞こえてくる。

 しかし、そう身構えないでほしい。LINQが目指すものは実のところ単純で、「データ処理の直交化と汎用化」である。この考え方は何もLINQで初めて取り組んだというものではなく、C# 1.0のころから、foreach文、ジェネリック、イテレータ・ブロックと、少しずつ進歩してきたものである。

 本稿はこの進歩の歴史を振り返るものである。

直交性

機能の“軸”

 ソフトウェア開発では、複雑な機能を単純な機能に分解することで、開発の難易度を下げるということがよく行われる。そして、機能を分解するに当たって、“軸”というものを意識することが有効である。

 今回のテーマであるLINQの用途、すなわち、データ処理について考えてみよう。データ処理の対象は、いわゆる「コレクション(collection)」である。そして、コレクションには、Figure 1に示すように、要素の型とアルゴリズムという2つの軸が考えられる。

Figure 1 コレクションの軸
配列などのいわゆるコレクション・クラスには、要素の型(=何を格納するか)とアルゴリズム(=どうやって要素を管理するか)の2つの軸がある。

 一般に、プログラムの基本は入力、計算、出力である。データ処理の場合、それぞれ、データの取得方法、加工方法、表示方法ということになるだろう。Figure 2に示すように、これらも軸を分けて考えられる。

Figure 2 データ処理の軸
入力=データの取得方法、計算=データの加工方法、出力=データの表示方法。取得元として先ほどのコレクションを考えると、さらに要素の型とアルゴリズムに軸が分かれる。

 データの加工方法は、さらに細かい軸に分かれる。複雑なデータ加工も、多くの場合、Figure 3に示すような単純な操作の組み合わせで表現できるのである。

Figure 3 データ加工の軸
データの加工は、さらに細かく見ると、選択(=特定の条件を満たす要素だけ残す)、変換(=要素ごとに何らかの演算を行う)、集計(=データ列全体を見て累算する)などの軸に分かれる。

機能の直交性

 それぞれの軸は独立しているべきである。すなわち、ある軸に新しい機能を追加したり、既存機能を修正したりした際に、別の軸に影響が出ないようにすべきだ。このような軸の独立性を、数学の言葉を借りて「直交性(orthogonality)」という。

 ここで、直交性がいかに重要な概念かを説明しよう。例として、以下のような3つの軸で、それぞれ3つずつ機能を考えよう。

  • 1つ目の軸に1、2、3
  • 2つ目の軸にi、ii、iii
  • 3つ目の軸にa、b、c

 軸が直交していないということは、「1-i-a」という組み合わせと、「1-i-b」という組み合わせをまったく別々に作る必要があるということである。もし直交していないまま全ての組み合わせについてプログラムを作るとなると、Figure 4に示すように、 通りのコードを書く必要がある。

Figure 4 直交性がない場合

 一方、軸が直交しているというのは、Figure 5に示すように、軸ごとに書いたコードの組み合わせで表現できることをいう。この場合、 通りのコードがあれば十分である。

Figure 5 直交性がある場合

 すなわち、軸を直交させるというのは、「必要となるコードの数を、掛け算から足し算に変える」という意味を持つ。

具体例 ジェネリック・コレクション

 分かりやすい例は、ジェネリック(Generics)導入前後におけるコレクションの変化だろう。int、double、stringという要素の型に対して、配列リスト(List)、連結リスト(LinkedList)、ハッシュテーブル(Hashtable)というアルゴリズムを使うことを考えてみよう。

 ジェネリック導入前は、以下のように、全ての組み合わせに特化した型を書く必要があった。

IntList、IntLinkedList、IntHashtable、DoubleList、DoubleLinkedList、……

 これが、ジェネリックの導入により、

List<int>、LinkedList<int>、Hashtable<int>、List<double>、LinkedList<double>、……

と書けるようになったわけである。コレクションの実装者は、List<T>、LinkedList<T>、Hashtable<T>という3つのジェネリック・コレクションを作るだけでよくなった。

掛け算を足し算に

 Figure 4、Figure 5の例は、3つの軸で、それぞれ3種類ずつですらこの差である。実際には、Figure 1〜Figure 3で見てきたように軸はもっと多いし、軸ごとの項目も多彩だ。掛け算と足し算の差は圧倒的である。試しに、5軸それぞれ10種類ずつを考えてみるといいだろう。

 掛け算のままでは話にならないのである。

 続いて次のページでは、軸の直交化からLINQ to Objectに至るまでの過程を説明する。


 INDEX
  特集:Road to LINQ
  C#で解説する「データ処理の直交化と汎用化」
  1.直交性
    2.LINQ to Objectに至るまで
    3.LINQ to ……/クエリ式

@IT Special

- PR -

TechTargetジャパン

Insider.NET フォーラム 新着記事
  • Microsoft Small Basic (2017/4/25)
     Microsoft Small Basicは学習を目的としてマイクロソフトが提供しているBASICの処理系。シンプルな言語仕様、習得が容易、簡潔な記述がその特徴
  • 第2回 Visual Studio 2017の基礎を知る (2017/4/21)
     開発環境Visual Studio 2017を使ったプログラミングに不可欠な知識とは? ソリューションの概念から画面構成まで基礎を説明
  • XmlSerializerでシリアライズ/デシリアライズする (2017/4/19)
     XmlSerializerクラスでシリアライズ/デシリアライズを行うと、デシリアライズに失敗することがある。その回避策を含め、XmlSerializerクラスの使い方を説明する
  • 二分探索 (2017/4/18)
     二分探索は、ソート済みのデータ列の中から特定の要素を探索するアルゴリズム。全ての要素を順に検索する線形探索よりも高速に探索を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

イベントカレンダー

PickUpイベント

- PR -

アクセスランキング

もっと見る

ホワイトペーパーTechTargetジャパン

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH