Skip to content

C#のLinqについての解説

こんにちは(/・ω・)/

今回もC#のLinqについての解説です。

前回でもメソッドを少し説明しましたが、今回はより範囲を広げてよく使うものと使えるものを書いていきたいと思います。

 

  • データの加工

データにフィルター処理をして必要なデータのみを集めたり、データを組み合わせて新しいデータを作ったりすることができます。

サンプルには

int[] numArray = { 1, 2, 3, 4, 5 };
int[] numArray2 = { 1, 1, 1, 2, 3, 5 };
string[] strArray = { "1", "2", "3", "4", "5" }; 
string[] strArray2 = { "6", "7", "8", "9", "10" };

を使用します。

 

  • Aggregate

アキュムレータ関数を適用する

 

アキュムレータとは?

例えば、1 + 2 + 3の計算をする時は

  1. 1 + 2を計算してその計算結果を保存する(結果をAとする)
  2. A + 3を計算する

のように2つずつ計算をしています。

この計算の過程で出てきたAのような一時的に計算結果を保持しておく領域のことをアキュムレータと言います。

このアキュムレータを使用すると、シーケンスの全要素を計算に利用することができます。

 

つまり、このメソッドを使用すればシーケンスの全ての要素を使う処理を簡単に書くことができます。

使い方次第で化ける面白いメソッドです。

var aggregate = strArray.Aggregate (( item, item2 ) => item + "☆" + item2); 
//1☆2☆3☆4☆5
/*
 * 1.itemと☆とitem2を連結させる
 * 2.連結した結果がitemになり、次の要素の計算に使用される
 */

計算結果は第1仮引数に保持されます。(上のサンプルではitemに保持されています)

var aggregate2 = strArray.Aggregate (( item, item2 ) => item2 + " " + item + " " + item2);
//5 4 3 2 1 2 3 4 5 

var aggregate3 = strArray.Aggregate (( item2, item ) => item2 + " " + item + " " + item2);
//1 2 1 3 1 2 1 4 1 2 1 3 1 2 1 5 1 2 1 3 1 2 1 4 1 2 1 3 1 2 1

 

オーバーロードではシードを設定する必要があります。

シードを設定すると、1回目の計算時のitemが引数で指定したものになります。

var aggregate4 = strArray.Aggregate ("☆", ( item, item2 ) => item + " " + item2);
//☆ 1 2 3 4 5

 

今回紹介する中ではこれが一番難しいと思います。後は大したことないです。

 

  • Select

シーケンスの各要素にラムダ式で指定した処理を行い、新しいシーケンスを作成する

//各要素に2倍したシーケンスを返す
var select = numArray.Select (item => item * 2);
//2 4 6 8 10

//インデックスを利用したい場合、第2仮引数に変数を宣言します。
var select2 = numArray.Select (( item, index ) => index.ToString () + " " + item * 2); 
//(0 2), (1 4), (2 6), (3 8), (4 10)

 

  • Skip

引数として受け取った数値分要素を飛ばして、残りのシーケンスを返す

 var skip = numArray.Skip (2); 
//3 4 5

 

  • SkipWhile

ラムダ式で指定した条件を満たしている間シーケンスの要素を飛ばして、満たさなくなったら残りの要素を返す

つまり、条件式がfalseになったら残りの要素を返す

var skipWhile = numArray2.SkipWhile (item => item < 2); 
//2 3 2 1

 

  • Take

引数として受け取った数値分シーケンスの要素を受け取る

var take = numArray.Take (2);
//1 2

 

  • TakeWhile

ラムダ式で指定した条件を満たしている間、シーケンスの要素を返す

満たさなくなったら処理を終了する

つまり、条件式がtrueの間の要素を返す

var takeWhile = numArray2.TakeWhile (item => item < 3); 
//1 2

 

  • Where

ラムダ式で指定した条件を満たすシーケンスの要素を返す

つまり、trueを通し、falseは通さない

var where = numArray.Where (item => item % 2 == 0); 
//2 4

 

  • Zip

2つのシーケンスの要素を使用して、新しいデータを作る

2つのシーケンスの要素数が異なる場合、少ない方に合わせる

var zip = strArray.Zip (strArray2, ( item, item2 ) => (item + " " + item2)); 
//(1 6), (2 7), (3 8), (4 9), (5 10)

 

SelectとWhereは特に使用する処理なので、覚えておくと便利です。

 

  • データの集計

サンプルには

int[] numArray = { 1, 2, 3, 4, 5 };
int[] numArray2 = { 1, 1, 1, 2, 3, 5 };

を使用します。

 

  • Average

平均値を求める

var average = numArray.Average (); //シーケンスの平均値を返す
//3

 

  • Count

要素の数を求める

var count = numArray.Count (); //要素数を返す
//5

var count2 = numArray2.Count (item => item == 1); //条件に合う要素数を返す
//3

 

  • Max

最大値を求める

var max = numArray.Max (); //シーケンスの最大値を返す
//5

 

  • Min

最小値を求める

var min = numArray.Min (); //シーケンスの最小値を返す
//1

 

  • Sum

合計を求める

var sum = numArray.Sum (); //シーケンスの合計値を返す
//15

 

特に複雑な操作は必要ありません。また、ラムダ式で指定すれば、絶対値で計算したりすることができます。

 

  • データの型変換

サンプルには

int[] numArray = { 1, 2, 3, 4, 5 };

を使用します。

 

  • ToArray

IEnumerable<T>からT[]に変換する

var toArray = numArray.Take (2).ToArray ();
Console.WriteLine (toArray.GetType ().ToString ());
//System.Int32[]

 

  • ToList

IEnumerable<T>からList<T>に変換する

var toList = numArray.ToList ();
Console.WriteLine (toList.GetType ().ToString ());
//System.Collections.Generic.List'1[System.Int32]

 

型変換についてはこの2つを使えるようになれれば、特に問題はないと思います。

 

  • データの判定

    このような状況の時にLinqメソッドで書き換えることができます。

foreach (var item in コレクション) 
{ 
    if (条件) 
    { 
        //処理 
    }
}

サンプルには

bool[] trueArray = { true, true, true }; 
bool[] boolArray = { true, false, true };
int[] numArray = { 1, 2, 3, 4, 5 };

を使用します。

 

  • All

シーケンスの全ての要素がラムダ式で指定した条件を満たしているか

var all = trueArray.All (item => item == true); 
//true

 

  • Any

シーケンスのどれかの要素がラムダ式で指定した条件を満たしているか

var any = boolArray.Any (item => item == false); 
//true

 

  • Contains

指定した要素がシーケンスに含まれているかどうか

var contains = numArray.Contains (1); //1があるかどうか
//true

 

  • データの集合

和集合、積集合、差集合の3つが扱えます。

サンプルには

int[] numArray = { 1, 2, 3, 4, 5 }; 
int[] oddArray = { 1, 3, 5, 7, 9 };
int[] evenArray = { 2, 4, 6, 8, 10 };

を使用します。

 

  • Union

2つのシーケンスから和集合を求める

var union = oddArray.Union (evenArray); //和集合 
//1 3 5 7 9 2 4 6 8 10

 

  • Intersect

2つのシーケンスから積集合を求める

var intersect = numArray.Intersect (evenArray); //積集合 
//2 4

 

  • Except

左のシーケンスから右のシーケンスを除いた差集合を求める

var except = numArray.Except (oddArray); //差集合 奇数を取り除く
//2 4
var except = oddArray.Except (numArray); //1~5の要素を取り除く
//7 9

 

  • データのソート

サンプルには

var dataArray = new[] {  
    new { A = 1, B = 1 },  
    new { A = 2, B = 2 },  
    new { A = 3, B = 2 },  
    new { A = 2, B = 3 },  
    new { A = 1, B = 0 }  
};

を使用します。

 

  • OrderBy

昇順に並び替える

//Aを基準に昇順で並び替える
var orderBy = dataArray.OrderBy (item => item.A); 
//結果 {1 1}{1 0}{2 2}{2 3}{3 2}

 

  • OrderByDescending

降順に並び替える

//Aを基準に降順で並び替える
var orderByDescenging = dataArray.OrderByDescending (item => item.A); 
//結果 {3 2}{2 2}{2 3}{1 1}{1 0}

 

  • ThenBy

昇順に並び替える

ただし、OrderByもしくはOrderByDescendingの後でないと使用できない

//Aを基準に昇順で並び替える、ただしAの値が同じ場合、Bの値を比較して昇順で並び替える。
var thenBy = dataArray.OrderBy (item => item.A).ThenBy (item => item.B); 
//結果 {1 0}{1 1}{2 2}{2 3}{3 2}

 

  • ThenByDescending

降順に並び替える

ただし、OrderByもしくはOrderByDescendingの後でないと使用できない

//Aを基準に昇順で並び替える。ただしAの値が同じ場合、Bの値を比較して降順で並び替える。
var thenByDescenging = dataArray.OrderBy (item => item.A)
    .ThenByDescending (item => item.B);
//結果 {1 1}{1 0}{2 3}{2 2}{3 2}

 

  • Reverse

順序を逆にする

var reverse = dataArray.Reverse ();
//結果 {1 0}{2 3}{3 2}{2 2}{1 1}

ThenByとThenByDescendingに関しては、それらの後ろにThenBy、ThenByDescendingを使うことによって、第3以降の並び替えの基準を設定することができます。

ソートに関してはかなり便利で、どんなデータ構造を持っているクラスであっても簡単にソートができるようになります。

 

  • データの探索

指定した要素を探して返す処理ができます。

サンプルには

int[] numArray = { 1, 2, 3, 4, 5 }; 

を使用します。

 

  • ElementAt
  • ElementAtOrDefault

引数として渡したインデックス位置にある要素を返す

引数が配列外の値だった場合、ElementAtは例外を投げ、ElementAtDefaultは型の規定値を返す(例えばintの規定値は0)

var elementAt = numArray.ElementAt (1); 
//2 
var elementAtDefault = numArray.ElementAtOrDefault (5); 
//0

 

  • First
  • FirstOrDefault

シーケンスの最初の要素を返す

もしくは、条件を満たす最初の要素を返す

シーケンスに要素がない場合、Firstは例外を投げ、FirstOrDefaultは型の規定値を返す

var first = numArray.First (item => item % 2 == 0); 
//2 
var firstOrDefault = numArray.FirstOrDefault (); 
//1

 

  • Last
  • LastOrDefault

シーケンスの最後の要素を返す

もしくは、条件を満たす最後の要素を返す

シーケンスに要素がない場合、Lastは例外を投げ、LastOrDefaultは型の規定値を返す

var last = numArray.Last (item => item % 2 == 0);//4 
var lastOrDefault = numArray.LastOrDefault (item => item == 7); //0

 

C#はなかなか奥が深い(~_~;)

他にもメソッドはありますが、(特にゲーム系のプログラミングでは)あまり使わないと思います。

一度サンプルを書いてみるとよく覚えられます

 

では(^_^)/

Published in2017年度前期