Skip to content

C#の便利な機能Linqについて

こんにちは( ̄ー ̄)

今回はC#のLinqという機能についてです。

 

Linqとは?

Linqは配列や配列を扱うクラス(例えばList<T>)のようなデータのかたまりを扱うクラスから情報を取得するための機能です。

Linqを利用するためには「using System.Linq;」が必要になります。

 

例えば、入力された文字列を半角スペースで区切って整数にしたい場合

string[] inputStr = Console.ReadLine ().Split (' '); //入力を受け付ける
int[] numArray = new int[inputStr.Length];            //変換後の受け皿を作る

for (int loop = 0; loop < inputStr.Length; loop++)
{
    numArray[loop] = int.Parse (inputStr[loop]);      //stringからintに変換
}

というようにループを回して処理をすれば整数に変換することができます。

 

ただ、Linqを利用すると

string[] inputStr = Console.ReadLine ().Split (' ');                   //入力を受け付ける

int[] numArray = inputStr.Select (str => int.Parse (str)).ToArray ();  //stringからintに変換

 

もしくは

int[] numArray = Console.ReadLine ().Split (' ').Select (str => int.Parse (str)).ToArray ();

というように書くこともできます。

 

まあ、Linqを使わなくてもfor文やwhile文を利用すれば処理できるので、必ずしも習得しないと困るというわけではないです。

 

Linqを利用するメリットとしては

  • データのかたまりに対してfor文while文を使用せずに、処理をすることができる(書くコードの量を減らせられればその分バグの発生を抑えられる)
  • 特に複雑な処理の場合、多重ネストのコードを書かずに済む
  • 文字数が少なくて楽

があります。

 

Linqが使える条件

厳密にはIEnumerable<T>インターフェースを継承しているかどうかです。

ですが、配列やList<T>などデータのかたまりを扱うようなクラスであれば大抵継承されているはずなので、現時点ではあまり気にしなくてもよいです。

 

Linqの記法

記法は2種類あります

  • クエリメソッド

サンプルで示したようなメソッドのように書いていくC#的なスタイルです。

メソッドの後にメソッドをつなげて書くこともできます。

 

  • クエリ構文

SQLのように書いていくスタイルです。

入力された文字列を半角スペースで区切って整数にするコードをクエリ構文で書いてみると

var result =
    from str in Console.ReadLine ().Split (' ')
    select int.Parse (str);

というようになります。

 

大まかな流れとしては

  • 結果を格納する変数を宣言
  • クエリ構文内の処理で使用する変数の宣言(from~)とどこからデータを持ってくるか(in~)を決める
  • データにどのような操作をするか
  • データをどのように返すか

になります。

ですが、自分はクエリメソッドを利用している人の方が多いという印象を持っています。

 

ここで少し話が変わりますが、Linqを最大限利用するためにはラムダ式の理解が必要になります。

 

ラムダ式とは?

Select (str => int.Parse (str))の「str => int.Parse (str)」に当たる部分がラムダ式というもので書かれています。

一部のクエリメソッドではメソッドに対してどんな処理をするか、ということを伝えなければならないです(例えば型変換をしろ!や偶数の要素を探せ!など)。

ラムダ式を利用するとどんな処理をするかということが簡単に書けるようになります。(簡単ではない書き方もあります)

 

記法は(仮引数) => (式) です。

また、仮引数が2つ以上ある場合は、それらをかっこで挟む必要があります。

 

ラムダ式が使用できるようになると

  • 何をするか指定しなければならないメソッド
  • プリミティブではないクラス(Vector3や自作クラスなど)

を自由に扱えるようになります。

(例えばVector3クラスのXのみの平均を求める処理や、X、Y、Zの優先度順でソートをするなどの処理)

 

サンプル

Vector3[] v = new Vector3[10];
float xAverage = v.Average (item => item.x);        //各座標の平均を求めてみる
float yAverage = v.Average (item => item.y);
float zAverage = v.Average (item => item.z);

//昇順のソートをする 左側にある方が優先度高い
v = v.OrderBy (item => item.x).ThenBy (item => item.y).ThenBy (item => item.z).ToArray ();

 

よく使うであろうメソッド

  • ToArray()

IEnumerable<T>で返ってくるデータをT[]に変換するメソッド

クエリメソッドによってはIEnumerable<T>という型で要素が返ってくるので、そのままでは不便なことがあります。なので、IEnumerable<T>をT[]に変換することによって、配列に格納できるようにします。

例えば、IEnumerable<int>で返ってきた結果に対してToArray()を使うとint型の配列になります。

 

  • Select()

全ての要素に対して指定された処理をするメソッド

Selectの引数として渡した処理を全ての要素に対して行います。

例えば、サンプルとして書いた「Select (str => int.Parse (str))」は「stringをintに変換する処理」を全ての要素に対して行うということになります。

 

  • Where()

指定された条件に対してtrueを返すものを通すメソッド

つまり条件を満たさないものは弾かれます

 

サンプル

int[] numArray = Console.ReadLine ().Trim ().Split (' ').Select (str => int.Parse (str)).ToArray ();
numArray = numArray.Where (item => item != 1).ToArray ();        //1を通さない

foreach (var item in numArray)
{
    Console.WriteLine (item);
}

結果

入力されたものから1が弾かれています。

 

最後に、紹介したメソッド以外にも使えるものはたくさんあります。

Linqに慣れると、もの凄く便利だと思います。

では(^_^)/

Published in2017年度前期