CLRオブジェクトに対するLINQ【C#】

C#ではLINQという配列・コレクションやその他のデータベースにおけるデータの集合に対する統一的な呼び出し方法を提供する仕組みがあります。これをうまく使うことでデータセットごとに使い方を覚える必要なく、学習コストを下げつつ読みやすいコーディングを行うことができます。

ここでは、特にLINQで配列・コレクションなどのCLRオブジェクトを操作する方法について概説します。

LINQとは?

LINQはC#においてCLRオブジェクト( 配列、コレクション etc. )、SQLデータベース、XMLなどのデータの集合に対する統一的な呼び出し方法を定めたものです。配列やコレクション、あるいは一般的なSQLデータベースなどではそれぞれで独自のデータの操作方法が定義されていることと思われますが、データベースごとに一つ一つの作法を覚えていくことは大きな負担になります。それを解決するために、どのようなデータの集合に対してでも同じ方法で呼び出せるようにしたのがLINQです。ここでは特にCLRオブジェクトに対するLINQ to Objectsについて説明します。

LINQ to ObjectsではIEnumerable<T>インターフェイスへの拡張メソッドとしてEnumerableクラスに定義されており、IEnumerable<T>インターフェイスを実装したオブジェクト(=配列やコレクションなど)への処理が可能です。ここで定義された拡張メソッドの引数には匿名メソッドで条件を指定します。その際にラムダ式を用いると簡単に条件の指定をすることができます。LINQというと敷居が高い印象もありますが、このようにLINQ自体は何か特殊な文法があるわけではなく、実はあくまでも拡張メソッドと匿名メソッドの組み合わせに過ぎないことが分かります。

なお、一応のちほど説明する「クエリ構文」というLINQ独自の文法はありますが、あくまでも通常の「メソッド構文」の簡略表現なので理解していなくても問題ありません。

LINQの構文

LINQはスタイルは通常のメソッドの呼び出しである「メソッド構文」と呼ばれている書き方が基本ですが、一部の処理に関してはメソッド構文を簡略化した「クエリ構文」というスタイルも使用可能です。ただし、「クエリ構文」ではすべてのLINQの処理を表現できるわけではなく、また通常のC#の書式とも異なりSQLに近い書き方なので、無理して使用する必要はないと思われます(実際には「クエリ構文」より「メソッド構文」の方がよく使われているようです)。

メソッド構文

基本書式
[データソース].[LINQメソッド]([条件]);
コード例
List<int> source_List = new List<int>() { 2, 4, 1, 7, 5, 10, 6, 13, 8, 11 };
var filtered_List = source_List.Where<int>(item => item >= 5);

IEnumerable<T>インターフェイスを実装したデータソースに対して、拡張メソッドとしてLINQのメソッドの定義がなされています(Enumerableクラス)。これらのLINQのメソッドは拡張メソッドなのでそのデータソースのインスタンスメソッドのように扱うことができ、LINQの処理を実行することができます。

コード例ではint型のリスト(source_List)に対して、Where<TSource>メソッドを用いて「5以上」という条件を満たす要素を取得しています。この際Where<int>メソッドの引数はFunc<int,bool>デリゲートであり、ラムダ式を用いて匿名メソッド「item => item >= 5」を引数としています。匿名メソッドやラムダ式については以下の記事をご覧ください。

LINQのメソッドで、戻り値がまたデータの集合になっているものはその型は基本的にIEnumerable<T>型になっているので、その戻り値に対してまたLINQが使えるという特徴があります(メソッドチェーン)。例えば次のように、Whereメソッドでフィルタリングしたうえで、その結果の最大値を求めるなどがメソッドを連続するだけで可能になります。

var filtered_List = source_List.Where<int>(item => item >= 5).Max();

クエリ構文

クエリ構文はSQLのSELECT文に類似した表現で記述することのできる構文です。この構文を用いて、フィルター処理、並べ替え、グループ化などのデータソースに対する操作を行うことができます。

基本書式 (例)
from [要素名] in [データソース] where [条件式] select [戻り値]
コード例
List<int> source_List = new List<int>() { 2, 4, 1, 7, 5, 10, 6, 13, 8, 11 };

var filtered_List =
    from item in source_List
    where item >= 5
    select item;

クエリ構文ではSQL文を逆順にしたような構文となります。コード例では先ほどのメソッド構文のコード例と同じ処理を表しています。ただし、クエリ構文ではLINQのすべての処理は表現できず、一般的にはメソッド構文を用いられることが多いようです。

主なLINQの処理を行う主なメソッド

LINQのメソッドはEnumerableクラスに定義されていますが、ここでは主なものをご紹介します。例として次のint型のリストに対してLINQを使って操作することを考えてみましょう。

List<int> sample = new List<int>() { 2, 4, 2, 6, 5, 1, 7, 5, 10, 9 };

データソースが条件を満たすかを判定するメソッド

Allメソッドデータソースのすべての要素が指定の条件を満たしているかどうかを判定します
Anyメソッドデータソースのいずれかの要素が指定の条件を満たしているかどうかを判定します
Containsメソッドデータソースに指定した値が含まれているかどうかを判定します
コード例
//sampleの要素がすべて5未満であるかどうかを判定する → False
var ret_all = sample.All(x => x < 5);

//sampleの要素に5未満の要素が含まれるかどうかを判定する → True
var ret_any = sample.Any(x => x < 5);

//sampleの要素に5が含まれるかどうかを判定する → False
var ret_contains = sample.Contains(5);

データソースを変換するメソッド

ToArrayメソッドデータソースを配列に変換します
ToListメソッドデータソースをリストに変換します
コード例
//sampleをリスト型から配列に変換する
var ret_toarray = sample.ToArray();

データソースの集計を行うメソッド

Averageメソッドデータソースの数値の平均値を取得します
Countメソッドデータソースの要素の個数を取得します
Maxメソッドデータソース中の最大値を取得します
Minメソッドデータソース中の最小値を取得します
Sumメソッドデータソースの数値の合計値を取得します
コード例
//sampleの要素の平均値を取得する → 5.1
var ret_average = sample.Average();

//sampleの要素数を取得する → 10
var ret_count = sample.Count();

//sampleの要素の最大値を取得する → 10
var ret_max = sample.Max();

//sampleの要素の最小値を取得する → 1
var ret_min = sample.Min();

//sampleの要素の合計値を取得する → 51
var ret_sum = sample.Sum();

データソースのソートを行うメソッド

OrderByメソッドデータソースを昇順に並べ替えます
OrderByDescendingメソッドデータソースを降順に並べ替えます
コード例
//sampleの要素を昇順に並べ替える → [1,2,2,4,5,5,6,7,9,10]
var ret_orderby = sample.OrderBy(x => x);

//sampleの要素を降順に並べ替える → [10,9,7,6,5,5,4,2,2,1]
var ret_orderbydescending = sample.OrderByDescending(x => x);

データソースから条件にあう要素を抽出するメソッド

Distinctメソッドデータソースから重複した要素を除外したものを取得します
ElementAtメソッドデータソースの指定した位置の要素を取得します
Firstメソッドデータソースで条件を満たす最初の要素を取得します
(条件を満たすものがない場合はエラー)
FirstOrDefaultメソッドデータソースで条件を満たす最初の要素を取得します
(条件を満たすものがない場合はデフォルト値(nullなど))
Lastメソッドデータソースで条件を満たす最後の要素を取得します
(条件を満たすものがない場合はエラー)
LastOrDefaultメソッドデータソースで条件を満たす最後の要素を取得します
(条件を満たすものがない場合はデフォルト値(nullなど))
Skipメソッドデータソースの先頭から指定した数の要素を除外したものを取得します
Takeメソッド先頭から指定した数の要素を取得します
Whereメソッド条件を満たす要素を取得します
コード例
//sampleの中から重複した要素を除外する → [2,4,6,5,1,7,10,9]
var ret_distinct = sample.Distinct();

//sampleの5番目の要素を取得する(先頭の要素が0番目) → 1
var ret_elementat = sample.ElementAt(5);

//sampleで最初に出現する3より大きい要素を取得する → 4
var ret_first = sample.First(x => x > 3);

//sampleで最後に出現する5より小さい要素を取得する → 1
var ret_last = sample.Last(x => x < 5);

//sampleの先頭から5文字を除外したものを取得する → [ 1,7,5,10,9]
var ret_skip = sample.Skip(5);

//sampleの先頭から5文字を取得する → [2,4,2,6,5]
var ret_take = sample.Take(5);

//sampleの要素で、5未満のものを取得する → [2,4,2,1]
var ret_where = sample.Where(x => x < 5);

データソースの射影を行うメソッド

Selectメソッドデータソースの個々の要素に何らかの処理を行って新しいデータセットを作成する
コード例
//sampleの各々の要素をそれぞれ2倍する → [4,8,4,12,10,2,14,10,20,18]
var ret_select = sample.Select(x => x * 2);

スポンサーリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)