LINQとCollectionは違うらしい【働学併進#005】
C#を勉強していた当初、LINQとは配列 Array やリスト List といった複数のデータを効率よく扱うための型だと勘違いしていた。
しかし本当のところは「Collectionは複数の要素を保持できる型」のことであり、「LINQはC#に組み込まれたクエリー技術 Language Integrated Query」だったのだ。
因みに、Queryとは「データの更新・削除・抽出・選択などの要求」のことである。例えば、noteの検索機能や自分の記事の削除もQueryである。
なぜ、わざわざC#の言語レベルで新たにクエリーを扱えるようにしたか。
それは「Collection型やSQL, XMLなどに対するクエリーの書き方を統合するため」だ。
つまり、「LINQとはCollection型やデータベース(SQL)などへの要求を同じように扱うためのC#の技術」とも言える。
冒頭だけでC#初学者(昔の私)の疑問の答えになっているだろうが、以降はCollectionとLINQについて、もう少し詳しくまとめる。
Collectionとは?
C#のCollection型は「複数の要素を保持できる型」と先ほど説明したが、実はCollectionには以下の3つの種類がある。
System.Collections のCollections
System.Collections.Generic のCollections
System.Collections.Concurrent のCollections
順にまとめる。
System.Collections のCollections
System.Collectionsのnamespace から呼び出せる以下のような型を用いることで、どのような型でもObject型として保持するコレクションを作ることができる。
ArrayList: サイズが動的に変わるコレクション
Hashtable: キーと値のペアのコレクション
Queue: First In, First Out (FIFO)のコレクション
Stack: Last In, First Out (LIFO)のコレクション
複数の型の項目 item を保持できるということは、コレクションから要素を取得するだけでもデータ型を判断、ときには変換する必要がある。だから、基本的には以下で紹介するCollections.GenericかCollections.Concurrentの名前空間 namespace のコレクションを使うことをMicrosoft も推奨してる。
Collections.Generic のCollections
System.Collections.Genericのnamespace から呼び出せる以下のような型を用いることでジェネリックコレクション(要素が全て同じ型のコレクション)を作成できる。
List<T>:
インデックスで項目 item を管理するコレクション
検索、並べ替え、変更のメソッドが用意されているDictionary<TKey, TValue>: キーと値のペアのコレクション
Queue<T>: First In, First Out (FIFO) のコレクション
Stack<T>: Last In, First Out (LIFO) のコレクション
「ジェネリック」という言葉から「さまざまな型を同時に保持できる」型だと勘違いするかもしれないが、正しくは「コレクションを宣言する際に指定された単一の方しか保持できないが、どのような型でも指示できる」という意味だ。
Collections.ConcurrentのCollections
System.Collections.Concurrent のnamespace から呼び出せる以下のような型を用いることで、スレッドセーフ thread-safe に項目 item にアクセスできるコレクションを作成できる。
BlockingCollection<T>: ブロッキングと範囲指定ができるコレクション
ConcurrentBag<T>: 順序づけられていない unordered なコレクション
ConcurrentDictionary<TKey, TValue>
ConcurrentQueue<T>: FIFO のコレクション
ConcurrentStack<T>: LIFO のコレクション
List vs. Array
どちらも「指定された1つの型の要素を複数保持できる」点や、foreachステートメントが使える(System.Collections.IEnumerableかSystem.Collections.Generic.IEnumerable<T>インターフェースを実装している)という点では同じだ。
しかし、Listはその大きさを動的に変えることができる一方、Arrayは宣言する際に指定した大きさのままである。
この違いを表すために、Arrayの要素数を取得するときは予め決められた長さという意味で .Length プロパティを使い、List などは動的に変化する要素数を数えるという意味で.Count プロパティを使う。
LINQとは?
前述の通り、LINQとは言語に組み込まれた、Collection やデータベースなどへのクエリーである。
因みに、LINQは「SQLのようにフィルター、並べ替え、グループなどを行うクエリー」と「Collection の各要素を扱うメソッド」という二つの意味で使われることがあり、前者をLINQクエリ、後者をLINQのメソッドなどと言われる(私的には好きでない)。
Filtering, Ordering, and Grouping
private static void ShowLINQ()
{
List<Element> elements = new List<Element>
{
{ new Element() { Symbol="K", Name="Potassium", AtomicNumber=19}},
{ new Element() { Symbol="Ca", Name="Calcium", AtomicNumber=20}},
{ new Element() { Symbol="Sc", Name="Scandium", AtomicNumber=21}},
{ new Element() { Symbol="Ti", Name="Titanium", AtomicNumber=22}}
};
var subset = from theElement in elements
where theElement.AtomicNumber < 22
orderby theElement.Name
select theElement;
foreach (Element theElement in subset)
{
Console.WriteLine(theElement.Name + " " + theElement.AtomicNumber);
}
// Output:
// Calcium 20
// Potassium 19
// Scandium 21
}
元素番号が22より小さく(where theElement.Atomic Number < 22)、アルファベット順に(orderby theElement.Name)、Element型のtheElementを要素とした(select theElement)コレクションを返す。
このように、from in, where, orderby, select などを使ったクエリ(クエリ式 query expression)に対して、以下で説明するようにメソッドのようにクエリを書くこともできる。
Standard Query Operator Extension Methods
標準クエリ演算子の拡張メソッド
LINQ標準クエリ演算子(LINQの拡張メソッド)とは、既存のSystem.Collections.IEnumerable かSystem.Collections.Generic.IEnumerable<T>型に追加された拡張メソッド。
クエリ式を、コレクションからメソッドを呼び出すように記述することができる。
因みに、ArrayもIEnmerableを実装しているためLINQ標準クエリ演算子が使える。
using System.Linq;
class ExtensionMethods2
{
static void Main()
{
int[] ints = { 10, 45, 15, 39, 21, 26 };
var result = ints.OrderBy(g => g);
foreach (var i in result)
{
System.Console.Write(i + " ");
}
}
}
// => 10 15 21 26 26 39 45
以下のことを忘れるべからず。
using System.Linq ディレクティブで、標準クエリ演算子をスコープに含める
標準クエリ演算子は元のデータを編集するものではないため、結果は別な変数で受け取る。
以下が標準クエリ演算子の一覧だが、詳しいことは公式ドキュメントを見てほしい。
並べ替え sort
OrderBy, OrderByDescending
ThenBy, ThenByDescending
Reverse
セット操作 set
Distinct[By]
Except[By]
Intersect[By]
Union[By]
フィルター処理 filter
Where, OfType
量指定子操作 quantifier
All
Any
Contains
射影操作
Select, SelectMany
Zip
パーティション分割 partition
Skip, SkipWhile, Take, TakeWhile
結合演算 join
Join, GroupJoin
グループ化 group
GroupBy, ToLookup
生成操作 generate
DefaultEmpty, Empty
Range
Repeat
等値演算 equality
SequenceEqual
要素操作 element operation
ElementAt, ElementAtOrDefault
First, FirstOrDefault
Last, LastOrDefault
Single, SingleOrDefault
データ型の変換 convert
AsEnumerable, AsQueryable, Cast, OfType
ToArray, ToDictionary, ToList, ToLookup
連結演算 concatenate
Concat
集計操作 aggregate
Aggregate
Average
Count, LongCount,
Max[By], Min[By]
Sum
#001から#005(月曜から金曜)までよく頑張った。
明日はゆっくり読書でもして、読書ノートを公開しよう。
この記事が気に入ったらサポートをしてみませんか?