Posted at

【C#】LINQ備忘録1 ~初級編~

More than 3 years have passed since last update.


【C#】LINQ備忘録1 ~初級編~

先月C#の案件をこなしている中で、LINQを触る機会があったのでメモ。

と~~~~っても使いやすくて、素敵な構文でした。C#すごいわほんと。

LINQについてはかなりの数の記事がありますので、あくまでこれは私の備忘録としてメモしておきます。


LINQって?


統合言語クエリ (LINQ, Language INtegrated Query, リンクと発音する)とは、.NET Framework 3.5において、様々な種類のデータ集合に対して標準化された方法でデータを問い合わせる(クエリ)ことを可能にするために、言語に統合された機能のことである。開発ツールはVisual Studio 2008から対応している。


今回の開発で用いたのは C#でのLINQ to Objectというヤツで、よくある形のforやforeach文で処理を行うのではなく、

一つの要素のカタマリに対してクエリを投げることで、射影(Select)を行ったり、選択(Where)を行ったりできます。

Java7でずーっと育ってきた私としては、中々このLINQの書き方には慣れ込めず、思ったよりも

コーディングに時間が掛かってしまいましたが、出来上がったコードはとーってもリーダブルで、

読みやすく、整ったコードになったと思います。余計な変数が生まれない高階関数って素晴らしいっすわ。

まだまだ勉強不足なところはありますが


  • Select

  • Where

  • Distinct

  • Concat

  • Skip

  • Take

あたりまでは使いこなせるようになったので、それぞれ備忘録としてササッと残しておきたいと思います。


Select(射影)

Selectは、要素全てに対して処理を行った結果を取り出します。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var points = new[] { 20, 30, 40, 40, 50 };
// 全て2倍した集合がほしい!

// ----------------- foreach版--------------------
// 結果を受け取る配列を用意
var result1 = new int[points.Length];
// ポインタを作成
var i = 0;
// 全て2倍して表示したい
foreach (var p in points)
{
// 配列に2倍した値を入力
result1[i] = p * 2;
// ポインタを更新
i++;
}
//画面に表示
Console.WriteLine(string.Join(",", result1));

// ----------------- Linq版--------------------
// 2倍した集合を取得
var result2 = points.Select(x => x * 2).ToArray();
//画面に表示
Console.WriteLine(string.Join(",", result2));
}

表示結果

image

従来のforeachを使ったコードよりも、圧倒的に行数が少なくなります。

Selectでは、要素それぞれに対して値を2倍し、それらの集合を取得しています。

今回、foreachのコードと比較するためToArray()を終端処理として入れていますが、

単に表示するだけであれば、これも必要ありません。


Where(選択)

Whereは、要素の中から指定した条件に合致するものを取り出します。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var points = new[] { 20, 30, 40, 40, 50 };
// 40以上の値だけ抜き出したい!

// ----------------- foreach版--------------------

// 結果を受け取るリストを用意
var result1 = new List<int>();
// 40以上の値だけ抜き出したい!
foreach (var p in points)
{
if(p >= 40)
{
// リストに値を追加
result1.Add(p);
}
}
//画面に表示
Console.WriteLine(string.Join(",", result1));

// ----------------- Linq版--------------------
// 40以上の値だけ抜き出したい!
var result2 = points.Where(x => x >= 40).ToList();
//画面に表示
Console.WriteLine(string.Join(",", result2));
}

表示結果

image

Selectと同様にArrayでやろうと思ったんですけど、foreach版が面倒になったのでListで取得することにします。

LINQ版は、Whereで40以上の条件指定し、それに合致するもののみ選択して取得しています。

終端処理はforeach版に合わせてListにしています。

これも、行数が削減され、可読性が上がっているのがわかると思います。

LINQは1行1行が意味のある処理となるのがいいですね。


Distinct

Distinctは、要素の中から重複しているものを排除します。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var points = new[] { 20, 30, 40, 40, 50 };
// 重複を排除したい!

// ----------------- foreach版--------------------

// 結果を受け取るリストを用意
var result1 = new List<int>();
// 重複を排除したい!
foreach (var p in points)
{
// すでに追加されていない場合
if(!result1.Contains(p))
{
// リストに値を追加
result1.Add(p);
}
}
//画面に表示
Console.WriteLine(string.Join(",", result1));

// ----------------- Linq版--------------------
// 重複を排除したい!
var result2 = points
.Distinct()
.ToList();
//画面に表示
Console.WriteLine(string.Join(",", result2));
}

表示結果

image

このメソッド、超便利っす。何も考えずにSQLのDistinctと同じ形で使えるし、

見栄えもとってもいいですね。


Concat

Concatは、要素と要素を連結させます。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var points1 = new[] { 20, 30, 40, 40, 50 };
// コレクションを用意
var points2 = new[] { 60, 70, 70, 80 };
// くっつける!

// ----------------- foreach版--------------------
// 結果を受け取るリストを用意
var result1 = new List<int>();
// くっつける!
foreach (var p in points1)
{
// points1の値を入れる
result1.Add(p);
}
// くっつける!
foreach (var p in points2)
{
// points2の値を入れる
result1.Add(p);
}
//画面に表示
Console.WriteLine(string.Join(",", result1));

// ----------------- Linq版--------------------
// くっつける!
var result2 = points1.Concat(points2).ToList();
//画面に表示
Console.WriteLine(string.Join(",", result2));
}

表示結果

image

Concatで一発です。すごい。


Skip

Skipは、要素を指定した数だけ読み飛ばします。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var points = new[] { 20, 30, 40, 40, 50 };
// 3つ飛ばして4つ目から見たい!

// ----------------- foreach版--------------------
// 結果を受け取るリストを用意
var result1 = new List<int>();
// 3つ飛ばして4つ目から見たい!
for (int i = 3; i < points.Length; i++)
{
// pointsの値を入れる
result1.Add(points[i]);
}
//画面に表示
Console.WriteLine(string.Join(",", result1));

// ----------------- Linq版--------------------
// 3つ飛ばして4つ目から見たい!
var result2 = points.Skip(3).ToList();
//画面に表示
Console.WriteLine(string.Join(",", result2));
}

表示結果

image

インデックスに関連する処理は、for文を使う必要があり、面倒なコードが増えてしまいます。

LINQと比較すると、差は歴然ですね。使いましょう。Skip。


Take

Takeは、要素を指定した数だけ読みます。

Skipと組み合わせると、範囲指定することもできます。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var points = new[] { 20, 30, 40, 40, 50 };
// 2つ目から4つ目まで見たい!

// ----------------- foreach版--------------------
// 結果を受け取るリストを用意
var result1 = new List<int>();
// 2つ目から4つ目まで見たい!
for (int i = 1; i < 4; i++)
{
// pointsの値を入れる
result1.Add(points[i]);
}
//画面に表示
Console.WriteLine(string.Join(",", result1));

// ----------------- Linq版--------------------
// 2つ目から4つ目まで見たい!
var result2 = points.Skip(1).Take(3).ToList();
//画面に表示
Console.WriteLine(string.Join(",", result2));

// ----------------- 表示--------------------
Console.ReadLine();
}

表示結果

image


おまけ ToDictionary

ToDictionaryは、Selectして得られる結果をDictionaryとして受け取ります。

/// <summary>

/// メインエントリ
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
// コレクションを用意
var productList = new Dictionary<string, int> {
{ "りんご", 200 },
{ "バナナ", 150 },
{ "すいか", 150 },
{ "ぶどう", 400 },
};
// 全てのValueを+50したDictionaryがほしい!

// ----------------- foreach版--------------------
// 結果を受け取るDictionaryを作成
var result1 = new Dictionary<string, int>();
// 全てのValueを+50したDictionaryを取得
foreach (var i in productList)
{
result1.Add(i.Key, i.Value + 50);
}
ShowConsole(result1);
// ----------------- Linq版--------------------
// 全ての要素を+50したDictionaryを取得
var result2 = productList
.ToDictionary(x => x.Key, x => x.Value + 50);
ShowConsole(result2);
}

/// <summary>
/// 表示用メソッド
/// </summary>
/// <param name="elements">表示するDictionary</param>
static void ShowConsole(Dictionary<string,int> elements)
{
// Key、Valueのペアを表示
Console.WriteLine(string.Join("\n", elements.Select(x => {
return x.Key + "\t" + x.Value;
})));
}

表示結果

image

Key、Valueそれぞれに対してSelectし、Dictionary化します。

実務上ではわざわざToDictionary()を加えて辞書にする必要は少ないかもしれませんが、

覚えておきたいと思います。


まとめ

SelectManyやToLookUpなど、他にも幾つか覚えることができたものがあるので、

そちらも近いうちに備忘録化したいと思っています。

LINQ素晴らしい!またC#案件が来るのを楽しみに待っていようと思います。