LINQの主要メソッド一覧
概要
このページではLINQでよく使用されるメソッドの解説を行います。
LINQについての概要はLINQを参照してください。
LINQ拡張メソッドにはオーバーロードがたくさんあります。
全部を解説するのは無理なので、使用頻度が高めと思われる物を解説します。
このページを読むときの注意
このページのサンプルコードの多くは実行結果の表示のコード(Console.WriteLine)は省略しています。
その場合の実行結果は単に変数の中身を表示しているだけです。
コレクションの中身を表示する場合のサンプルコードはLINQのページにあります。
メソッドの戻り値を受け取る変数宣言ではデータ型を明示していますが、メソッドによって返されるデータ型が変わるので型推論(var)で受け取ったほうが良いと思います。
特に説明がない限り、このページのサンプルコードで「Test」というクラスが登場した場合、以下の自作クラスを使用します。
class Test
{
public int Num;
public string Str;
public Test(int n, string s)
{
Num = n;
Str = s;
}
}
要素の比較が必要なメソッドについて
LINQのいくつかのメソッドは内部的に要素同士を比較するものがあります。
例えば要素の並び替えをするOrderByメソッドは要素同士を比較して並べ替えの順序を決定しています。
これらのメソッドで比較の方法を自分で定義するには特定のインターフェイスの継承や比較のためのクラスの定義などが必要となります。
具体的な方法はオブジェクトの比較を参照してください。
メソッド一覧
シーケンスの生成
Enumerable.Repeat
Enumerable.Range
Enumerable.Repeatメソッドは指定の要素を指定の数だけ生成して返します。
Enumerable.Rangeメソッドは指定の要素から指定の数連続させた要素を返します。
//要素が「2」、要素数「5」のシーケンスを返す
IEnumerable<int> repeat = Enumerable.Repeat(2, 5);
//「2」から5つ分要素が連続するシーケンスを返す
IEnumerable<int> range = Enumerable.Range(2, 5);
2 2 2 2 2 2 3 4 5 6
変換
ToArray
ToList
ToDictionary
ToArrayメソッドはシーケンスを配列に変換します。
ToListメソッドはシーケンスをListに変換します。
ToDictionaryメソッドはシーケンスをDictionaryに変換します。
ToDictionaryメソッドは第一引数のみを指定するとKeyは第一引数の値に、Valueはシーケンスの要素となります。
第二引数を指定すると、Valueはその引数の値となります。
ToDictionaryのKeyに重複要素がある場合は例外が発生します。
重複の可能性がある場合はあらかじめDistinctなどで重複要素を除去しておく必要があります。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc")
};
Test[] toArray = tests.ToArray();
List<Test> toList = toArray.ToList();
Dictionary<int, Test> toDictionary1 =
tests.ToDictionary(x => x.Num);
//↑は↓と同じ
//Dictionary<int, Test> _toDictionary1 = new Dictionary<int, Test>()
//{
// { 1, tests[0] },
// { 2, tests[1] },
// { 3, tests[2] }
//};
Dictionary<int, string> toDictionary2 =
tests.ToDictionary(x => x.Num, x => x.Str);
//↑は↓と同じ
//Dictionary<int, string> _toDictionary2 = new Dictionary<int, string>()
//{
// { 1, "aaa" },
// { 2, "bbb" },
// { 3, "ccc" }
//};
IEqualityComparer
ToDictionaryメソッドのオーバーロードにはIEqualityComparerを引数に取るものがあります。
これはキーに指定する要素の比較のためのクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型をキーにする、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
AsEnumerable
AsEnumerableメソッドはシーケンスをIEnumrableに変換します。
これはEnumerableクラスで定義されているメソッド(LINQ拡張メソッド)を明示的に呼び出したい場合に使用します。
例えばLINQにはReverseというメソッドがありますが、ListクラスにもReverseメソッドがあり、そのまま記述するとListクラスのほうが呼ばれます。
AsEnumerableでIEnumrableに変換してからReverseメソッドを呼び出せばLINQのReverseメソッドが呼ばれます。
List<int> nums = new List<int>()
{
11, 5, 9, 4, 6
};
IEnumerable<int> reverse = nums.AsEnumerable().Reverse();
//↓これだとListクラスのReverseメソッドが呼ばれてしまう
//IEnumerable<int> reverse = nums.Reverse();
ToLookup
ToLookupメソッドは要素を指定のキーでグループ化します。
このメソッドはGroupByと良く似ており、使用方法もほぼ同じです。
ただしGroupByメソッドで可能な「データ型の変換」はToLookupメソッドではできません。
グループ化というのはあるキーが共通する要素同士を同じグループに分類して格納する、という意味です。
以下の例ではTestクラスのフィールドNumをキーとし、フィールドNumが同じもの同士をまとめて格納しています。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
ILookup<int, Test> toLookup =
tests.ToLookup(x => x.Num);
foreach (var x in toLookup)
{
Console.Write(x.Key);
foreach (Test t in x)
Console.Write(" {0}", t.Str);
Console.WriteLine();
}
1 aaa ddd 2 bbb 3 ccc eee
戻り値はDictionaryクラスに似た構造の「ILookup」というデータ型です。
Dictionaryクラスは「ひとつのKeyに対してひとつのValue」というものですが、ILookupは「ひとつのKeyに対して複数のValue」といった感じの構造です。
この「複数のValue」に、同じグループの要素がまとめて格納されています。
(ただし「Key」プロパティはありますが「Value」プロパティはありません)
「ジャグ配列(配列の配列)」と考えたほうが分かりやすいかもしれません。
グループ化される要素の指定
第二引数でグループ化対象の要素を指定することもできます。
以下の例ではフィールドStrをグループ化される要素にしています。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
//型引数が<int, string>に変わっている
ILookup<int, string> toLookup =
tests.ToLookup(
x => x.Num,
x => x.Str);
foreach (var x in toLookup)
{
Console.Write(x.Key);
foreach (string s in x)
Console.Write(" {0}", s);
Console.WriteLine();
}
1 aaa ddd 2 bbb 3 ccc eee
IEqualityComparer
ToLookupメソッドのオーバーロードにはIEqualityComparerを引数に取るものがあります。
これはキーの比較の方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型をキーにする、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
Cast
Castメソッドは要素を指定のデータ型にキャストします。
キャストできない要素が含まれている場合は例外が発生します。
Castメソッドはよくある「int型→long型」のようなキャストはできません。
クラスのアップキャストやダウンキャスト用のメソッドです。
class Base
{
//実装は省略
}
class Test : Base
{
//実装は省略
}
//アップキャスト
List<Base> tests = new List<Base>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc")
};
//ダウンキャスト
IEnumerable<Test> cast = tests.Cast<Test>();
OfType
OfTypeメソッドは要素を指定のデータ型にキャストします。
キャストできない要素が含まれている場合は結果から除外されます。
OfTypeメソッドはよくある「int型→long型」のようなキャストはできません。
クラスのアップキャストやダウンキャスト用のメソッドです。
class Base
{
//実装は省略
}
class TestA : Base
{
//実装は省略
}
class TestB : Base
{
//実装は省略
}
//アップキャスト
List<Base> tests = new List<Base>()
{
new TestA(1, "aaa"),
new TestB(2, "bbb"), //違う型が混ざっている
new TestA(3, "ccc")
};
//ダウンキャスト
IEnumerable<TestA> ofType = tests.OfType<TestA>();
1 aaa 3 ccc
単一要素の取得
First
Last
ElementAt
Single
Firstメソッドは最初の要素を返します。
Lastメソッドは最後の要素を返します。
ElementAtメソッドは指定のインデックスの要素を返します。
Singleメソッドはシーケンスに要素がひとつだけ存在する場合に、その要素を返します。
これらのメソッドは該当する要素がない場合は例外が発生します。
Singleメソッドはシーケンスに要素が二つ以上ある場合も例外が発生します。
List<int> nums = new List<int>()
{
1, 2, 5, 9, 11, 14, 18, 21
};
int first = nums.First();
int last = nums.Last();
int elementAt = nums.ElementAt(2);
List<int> nums2 = new List<int>()
{
9
};
int single = nums2.Single();
1 21 5 9
条件の指定
First、Last、Singleメソッドは引数に条件を指定することもできます。
Firstメソッドは先頭から数えて最初に条件に合致する要素を返します。
Lastメソッドは末尾から数えて最初に条件に合致する要素を返します。
Singleメソッドは条件に合致するひとつの要素を返します。
該当する要素がない場合は例外が発生します。
Singleメソッドは該当する要素が二つ以上ある場合も例外が発生します。
Singleメソッドはほとんどの場合でこちらが使用されるでしょう。
List<int> nums = new List<int>()
{
1, 2, 5, 9, 11, 14, 18, 21
};
int first = nums.First(x => x % 2 == 0);
int last = nums.Last(x => x % 2 == 0);
int single = nums.Single(x => x > 20);
2 18 21
FirstOrDefault
LastOrDefault
ElementAtOrDefault
SingleOrDefault
これらは基本的にFirstメソッドなどと同じですが、該当する要素が存在しない場合に規定値を返します。
(例外は発生しません)
SingleOrDefaultメソッドは該当する要素が二つ以上ある場合も規定値を返します。
ElementAtOrDefault以外は引数に条件が指定できます。
List<int> nums = new List<int>()
{
//空
};
int first = nums.FirstOrDefault();
int last = nums.LastOrDefault();
int elementAt = nums.ElementAtOrDefault(2);
int single = nums.SingleOrDefault(x => x > 20);
0 0 0 0
複数要素の取得
Where
Whereメソッドは条件に合う要素をすべて返します。
List<int> nums = new List<int>()
{
1, 2, 5, 9, 11, 14, 18, 21
};
IEnumerable<int> where = nums.Where(x => x > 10);
11 14 18 21
要素番号の使用
以下のように引数を二つ取るメソッドを指定すると、現在操作中の要素のインデックス(要素番号)をメソッド内で使用できます。
List<int> nums = new List<int>()
{
1, 2, 5, 9, 11, 14, 18, 21
};
//要素番号が3以上、かつ奇数の要素を取得
IEnumerable<int> where = nums.Where(
(num, index) => index >= 3 && num % 2 != 0);
9 11 21
Take
Skip
Takeメソッドは先頭から指定した数の要素を返します。
Skipメソッドは先頭から指定の数を省いた要素を返します。
List<int> nums = new List<int>()
{
1, 2, 5, 9, 11, 14, 18, 21
};
IEnumerable<int> take = nums.Take(3);
IEnumerable<int> skip = nums.Skip(3);
1 2 5 9 11 14 18 21
TakeWhile
SkipWhile
TakeWhileメソッドは先頭から条件を満たす要素を返します。
(条件を満たさなくなるまでの要素を返す)
SkipWhileメソッドは先頭から条件を満たす要素を省略し、残りを返します。
これらは条件を満たさなくなった要素以降に条件を満たす要素があっても無視されます。
引数を二つ取るメソッドを指定すると、現在操作中の要素のインデックス(要素番号)をメソッド内で使用できます。
List<int> nums = new List<int>()
{
1, 2, 5, 9, 11, 14, 3, 4
};
IEnumerable<int> takeWhile = nums.TakeWhile(x => x < 10);
IEnumerable<int> skipWhile = nums.SkipWhile(x => x < 10);
//要素のindexを使用する場合
//要素番号3未満、かつ要素の値が10未満
IEnumerable<int> takeWhile2 = nums.TakeWhile(
(num, index) => index < 3 && num < 10);
1 2 5 9 11 14 3 4 1 2 5
DefaultIfEmpty
DefaultIfEmptyメソッドはシーケンスが空の場合に規定値または任意の要素をひとつ持つシーケンスを返します。
シーケンスが空でない場合はそのシーケンスを返します。
List<int> nums1 = new List<int>()
{
1, 2, 3
};
List<int> nums2 = new List<int>();
IEnumerable<int> defaultIfEmpty1 = nums1.DefaultIfEmpty();
IEnumerable<int> defaultIfEmpty2 = nums2.DefaultIfEmpty();
IEnumerable<int> defaultIfEmpty3 = nums2.DefaultIfEmpty(-1);
1 2 3 0 -1
シーケンスが空の場合、そのデータ型の規定値をひとつ持つシーケンスが返されます。
引数に任意の値を指定すると、規定値の代わりにその値を要素にひとつ持つシーケンスが返されます。
この値は自作クラスなどでも可能です。
Distinct
Distinctメソッドは重複要素を省いたシーケンスを返します。
List<int> nums = new List<int>()
{
1, 2, 5, 2, 4, 5
};
IEnumerable<int> distinct = nums.Distinct();
1 2 5 4
IEqualityComparer
DistinctメソッドのオーバーロードにはIEqualityComparerを引数に取るものがあります。
これはキーの比較の方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型をキーにする、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
ただし、比較クラスを用意するのは少し面倒なので、Distinctは使用せずにGroupByとSelectを組み合わせて実現する方法もあります。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(1, "aaa")
};
IEnumerable<Test> distinct =
tests.GroupBy(x => x.Num)
.Select(group => group.First());
foreach (var x in distinct)
Console.WriteLine("{0} {1}", x.Num, x.Str);
1 aaa 2 bbb
指定のキーでグループ化した後、グループの先頭要素のみを取り出すことで重複を除去しています。
それぞれのメソッドの詳しい動作はGroupByとSelectを参照してください。
データの集計
Count
Countメソッドはシーケンスの要素数を返します。
引数に条件式を指定すると、条件に合致する要素数を返します。
List<int> nums = new List<int>()
{
8, 11, 5, 21, 7
};
int count1 = nums.Count();
int count2 = nums.Count(x => x < 10);
5 3
Min
Max
Minメソッドはシーケンス中の最小値を返します。
Maxメソッドはシーケンス中の最大値を返します。
List<int> nums = new List<int>()
{
8, 11, 5, 21, 7
};
int min = nums.Min();
int max = nums.Max();
5 21
これらは比較対象のデータ(フィールド、プロパティ)を引数で指定することができます。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc")
};
int min = tests.Min(x => x.Num);
int max = tests.Max(x => x.Num);
1 3
Sum
Average
Sumメソッドはシーケンスの要素を合計した値を返します。
Averageメソッドはシーケンスの要素の平均を返します。
List<int> nums = new List<int>()
{
8, 11, 5, 21, 7
};
int sum = nums.Sum();
double average = nums.Average();
52 10.4
これらは計算に使用するデータ(フィールド、プロパティ)を引数で指定することができます。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc")
};
int sum = tests.Sum(x => x.Num);
double average = tests.Average(x => x.Num);
6 2
Aggregate
Aggregateメソッドはデータ集計の方法を自ら設計することができます。
SumやAverageなどと同じ計算もこのメソッドで行うことができます。
Aggregateメソッドは使用方法がやや難解で、オーバーロードも含めて理解しなければ有効に使用することができません。
しかしかなり自由な処理をさせることができるので、使い方次第では便利なメソッドです。
引数ひとつ(func)
List<int> nums = new List<int>()
{
1, 2, 3, 4, 5
};
//Sumと同等の処理
int agregate = nums.Aggregate((x, y) => x + y);
15
Aggregateメソッドは、メソッド(func)をひとつ与える形があります。
(デリゲート、ラムダ式)
このメソッドは引数をふたつ取り、以下のような動作となります。
- numsから要素を一つ取り出しxに格納
- numsから次の要素を取り出しyに格納
- 式を実行し、結果をxに格納
- 2~3をすべての要素分繰り返し、xを返す
実際の値に置き換えると、
- 1 + 2
- 3 + 3
- 6 + 4
- 10 + 5
となり、結果は「15」となります。
引数ふたつ(seed, func)
メソッドの前にseedと呼ばれる値を与えると、上記の「1」の手順の際にこのseedがxに格納されます。
このseedはシーケンスの要素と同じ型である必要はなく、例えば以下のように文字列結合を行うこともできます。
List<int> nums = new List<int>()
{
1, 2, 3, 4, 5
};
string agregate = nums.Aggregate("", (x, y) => x + y);
12345
このコードの実行結果は数値(int型)ではなく「12345」という文字列であることに注意してください。
引数みっつ(seed, func, resultSelector)
seed、funcに続いて第三引数にresultSelectorというメソッドを与えることができます。
これはすべての要素に対するfuncの実行が終わった後、最後に呼び出されます。
List<int> nums = new List<int>()
{
1, 2, 3, 4, 5
};
//Averageと同等の処理
double agregate = nums.Aggregate(
0,
(x, y) => x + y,
x => x / (double)nums.Count);
3
resultSelectorの引数はひとつで、ここにfuncの実行結果が格納されます。
このサンプルではすべての要素を加算した後に要素数で割っているので、つまり平均値を求めています。
(キャストしているのは結果をdouble型にするためです)
集合
Union
Except
Intersect
Unionメソッドは二つのシーケンスの和集合を返します。
これは両方のシーケンスの要素を、重複要素を省いてすべて合わせた新しいシーケンスを作ります。
Exceptメソッドは二つのシーケンスの差集合を返します。
これは実行対象のシーケンスから、引数指定のシーケンス中に存在する要素を省いた新しいシーケンスを作ります。
Intersectメソッドは二つのシーケンスの積集合を返します。
これは実行対象のシーケンスから、引数指定のシーケンス中に存在する要素を抽出した新しいシーケンスを作ります。
List<int> nums1 = new List<int>()
{
3, 5, 9, 12, 15
};
List<int> nums2 = new List<int>()
{
4, 5, 9, 11, 15
};
IEnumerable<int> union = nums1.Union(nums2);
IEnumerable<int> except = nums1.Except(nums2);
IEnumerable<int> intersect = nums1.Intersect(nums2);
3 5 9 12 15 4 11 3 12 5 9 15
IEqualityComparer
これらのメソッドはIEqualityComparerを引数に取るオーバーロードもあります。
これは要素の比較の方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型を比較する、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
結合
Concat
Concatメソッドは二つのシーケンスを結合します。
List<int> nums1 = new List<int>()
{
1, 2, 3
};
List<int> nums2 = new List<int>()
{
2, 3, 4
};
IEnumerable<int> concat = nums1.Concat(nums2);
1 2 3 2 3 4
Join
Joinメソッドは二つのシーケンスの共通するキーを用いて結合し、新しいシーケンスを作り出します。
//役職
class Position
{
public int ID;
public string Name;
public Position(int id, string name)
{
ID = id;
Name = name;
}
}
//人物
class Person
{
public int ID;
public string Name;
public int PositionID;
public Person(int id, string name, int positionID)
{
ID = id;
Name = name;
PositionID = positionID;
}
}
//社員
class Employee
{
public string Position;
public string Name;
public Employee(string position, string name)
{
Position = position;
Name = name;
}
}
static void Main(string[] args)
{
List<Position> positions = new List<Position>()
{
new Position(1, "部長"),
new Position(2, "課長"),
new Position(3, "係長"),
new Position(4, "ヒラ"),
};
List<Person> persons = new List<Person>()
{
new Person(1, "A山B太", 1),
new Person(2, "C谷D男", 2),
new Person(3, "E下F子", 2),
new Person(4, "G田H雄", 3),
new Person(5, "I森J美", 3),
new Person(6, "K川L子", 4),
new Person(7, "M沢N助", 4),
new Person(8, "O木P一", 4),
};
IEnumerable<Employee> employees = positions.Join(
persons,
position => position.ID,
person => person.PositionID,
(position, person) => new Employee(position.Name, person.Name));
}
部長 A山B太 課長 C谷D男 課長 E下F子 係長 G田H雄 係長 I森J美 ヒラ K川L子 ヒラ M沢N助 ヒラ O木P一
このコードはPositionクラスのフィールド「ID」と、Personクラスのフィールド「PositionID」を共通のキーとし、二つのクラス(のフィールド)同士を結合してEmployeeという新しいクラスを作り出しています。
Joinメソッドの第一引数には結合するシーケンスを指定します。
第二引数は結合されるシーケンスのキーを指定します。
第三引数は結合するシーケンス(第一引数のシーケンス)のキーを指定します。
第四引数はそれぞれのシーケンスから必要なフィールドを取り出して新しいデータ型を生成するためのメソッド(ラムダ式)を指定します。
今回はPersonクラスの「Name」とPositonクラスの「Name」を使ってEmployeeクラスを作り出しています。
新しいクラス型(今回はEmployeeクラス)をわざわざ用意する必要がなければ匿名型でも構いません。
IEqualityComparer
JoinメソッドにはIEqualityComparerを引数に取るオーバーロードもがあります。
これはキーの比較の方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型をキーにする、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
GroupJoin
GroupJoinメソッドは二つのシーケンスの共通するキーを用いて新しいシーケンスを作り出します。
新しいシーケンスはキー毎にグループ分けされます。
//役職
class Position
{
//Joinメソッド参照
}
//人物
class Person
{
//Joinメソッド参照
}
//社員
class Employee
{
public string Position;
public List<Person> Persons;
public Employee(string position, List<Person> persons)
{
this.Position = position;
this.Persons = persons;
}
}
static void Main(string[] args)
{
List<Position> positions = new List<Position>()
{
new Position(1, "部長"),
new Position(2, "課長"),
new Position(3, "係長"),
new Position(4, "ヒラ"),
};
List<Person> persons = new List<Person>()
{
new Person(1, "A山B太", 1),
new Person(2, "C谷D男", 2),
new Person(3, "E下F子", 2),
new Person(4, "G田H雄", 3),
new Person(5, "I森J美", 3),
new Person(6, "K川L子", 4),
new Person(7, "M沢N助", 4),
new Person(8, "O木P一", 4),
};
IEnumerable<Employee> employees = positions.GroupJoin(
persons,
position => position.ID,
person => person.PositionID,
(position, _persons) => new Employee(position.Name, _persons.ToList()));
}
部長 A山B太 課長 C谷D男 E下F子 係長 G田H雄 I森J美 ヒラ K川L子 M沢N助 O木P一
「Positionクラス」と「Personクラス」はJoinメソッドの解説と同じですのでそちらを参照してください。
Joinメソッドとの違いは、第四引数に指定するメソッドの第二引数(_persons)が、共通するキーを持つ要素でグループ化(シーケンス化)されている点です。
IEqualityComparer
GroupJoinメソッドにはIEqualityComparerを引数に取るオーバーロードもがあります。
これはキーの比較の方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型をキーにする、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
Zip
Zipメソッドは二つのシーケンスの要素同士を任意のルールで合体させます。
(.NET Framework4以降)
int[] nums = new int[]
{
1, 2, 3, 4, 5
};
List<string> strs = new List<string>()
{
"a", "bb", "ccc"
};
//単純な結合
IEnumerable<string> joins1 = nums.Zip(
strs,
(n, s) => n + s);
//数値を文字数で乗算
IEnumerable<int> joins2 = nums.Zip(
strs,
(n, s) => n * s.Length);
1a 2bb 3ccc 1 4 9
第一引数は結合する対象のシーケンスを指定します。
データ型に制限はありません。
第二引数は合体させるルールとなるメソッドを指定します。
引数はふたつで、第一引数が結合されるシーケンス(nums)、第二引数が第一引数に指定したシーケンス(strs)の各要素となります。
それぞれのシーケンスの同じ要素番号同士の要素を結合させるので、戻り値となるシーケンスの要素数は要素が少ない方のシーケンスの要素数となります。
判定
Contains
All
Any
SequenceEqual
Containsメソッドは要素が含まれているかを判定します。
Allメソッドはすべての要素が条件を満たすかを判定します。
Anyメソッドはいずれかの要素が条件を満たすか(ひとつでも条件を満たすか)を判定します。
SequenceEqualメソッドは別のシーケンスと要素が等しいかを判定します。
Anyメソッドは引数を指定しない場合、シーケンスに何らかの要素が存在する場合に真を返します。
ContainsメソッドはListにそのまま適用するとListクラス内で定義されているContainsメソッドが呼び出されるため、AsEnumerableメソッドを利用して呼び出しています。
List<int> nums1 = new List<int>()
{
3, 5, 9, 12, 15
};
List<int> nums2 = new List<int>()
{
3, 5, 9, 12, 15
};
bool contains = nums1.AsEnumerable().Contains(12);
bool all = nums1.All(x => x < 10);
bool any1 = nums1.Any();
bool any2 = nums1.Any(x => x < 10);
bool sequenceEqual = nums1.SequenceEqual(nums2);
true false true true true
IEqualityComparer
Contains、SequenceEqualメソッドはIEqualityComparerを引数に取るオーバーロードもあります。
これは要素の比較方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型を比較する、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。
ソート(並べ替え)
OrderBy
OrderByDescending
Reverse
OrderByメソッドは要素を昇順で並べ替えたシーケンスを返します。
OrderByDescendingメソッドは要素を降順で並べ替えたシーケンスを返します。
Reverseメソッドは要素の順序を前後反転させたシーケンスを返します。
List<int> nums = new List<int>()
{
11, 5, 9, 4, 6
};
IEnumerable<int> orderBy = nums.OrderBy(x => x);
IEnumerable<int> orderByDescending = nums.OrderByDescending(x => x);
IEnumerable<int> reverse = nums.AsEnumerable().Reverse();
4 5 6 9 11 11 9 6 5 4 6 4 9 5 11
ReverseメソッドはListにそのまま適用するとListクラス内で定義されているReverseメソッドが呼び出されるので、AsEnumerableメソッドを利用して呼び出しています。
IComparer
OrderBy、OrderByDescendingメソッドはIComparerを引数に取るオーバーロードもあります。
これは要素の比較方法を指定したクラス(IComparerを継承したクラス)を指定します。
例えば独自の比較方法を使用する、クラスのメンバーで比較する、などの場合に使用されます。
詳細はIComparerを参照してください。
ThenBy
ThenByDescending
ThenByメソッドはソートされたシーケンス内で同じ順位の要素を昇順で並べ替えます。
ThenByDescendingメソッドはソートされたシーケンス内で同じ順位の要素を降順で並べ替えます。
これらは要するに、並べ替えの順序が同じ要素があった場合に、次の並べ替え条件となる値を指定することができます。
List<Test> tests = new List<Test>()
{
new Test(5, "aaa"),
new Test(8, "bbb"),
new Test(2, "ccc"),
new Test(2, "ddd"),
new Test(8, "eee")
};
IEnumerable<Test> thenBy =
tests.OrderBy(x => x.Num)
.ThenBy(x => x.Str);
IEnumerable<Test> thenByDescending =
tests.OrderBy(x => x.Num)
.ThenByDescending(x => x.Str);
foreach (var t in thenBy)
Console.WriteLine("{0} {1}", t.Num, t.Str);
Console.WriteLine();
foreach (var t in thenByDescending)
Console.WriteLine("{0} {1}", t.Num, t.Str);
2 ccc 2 ddd 5 aaa 8 bbb 8 eee 2 ddd 2 ccc 5 aaa 8 eee 8 bbb
IComparer
ThenBy、ThenByDescendingメソッドはIComparerを引数に取るオーバーロードもあります。
これは要素の比較方法を指定したクラス(IComparerを継承したクラス)を指定します。
例えば独自の比較方法を使用する、クラスのメンバーで比較する、などの場合に使用されます。
詳細はIComparerを参照してください。
射影
Select
Selectメソッドはそれぞれの要素に式を適用したシーケンスを返します。
以下の例では、numsの各要素を二倍したシーケンスを返します。
メソッドの引数を二つ指定すると、現在操作中の要素のインデックス(要素番号)をメソッド内で使用できます。
List<int> nums = new List<int>()
{
11, 5, 9, 4, 6
};
IEnumerable<int> select = nums.Select(x => x * 2);
//要素のindexを使用する場合
//要素番号が3以上の要素を二倍にする
IEnumerable<int> select2 = nums.Select(
(num, index) => index >= 3 ? num * 2 : num);
22 10 18 8 12 11 5 9 8 12
戻り値の型は自由です。
newでクラスのシーケンスを得ることもできますし、クラスからメンバーのシーケンスを得ることもできます。
List<string> strs = new List<string>()
{
"aaa", "bbb", "ccc"
};
//「Test」型のシーケンスを得る
IEnumerable<Test> select1 = strs.Select(
(s, index) => new Test(index, s));
//「string」型のシーケンスを得る
IEnumerable<string> select2 =
select1.Select(t => t.Str);
1 aaa 2 bbb 3 ccc aaa bbb ccc
SelectMany
SelectManyメソッドはシーケンスの要素がシーケンスであるとき、各要素に式を適用した上で平坦化して返します。
要するに、「配列の配列」のような構造のシーケンスに対し、各要素にメソッドを適用し、「ただの配列」にして返します。
データ構造が「配列の配列」から「配列」に変換され、これを平坦化というそうです。
(実際に返ってくるのはIEnumerable型です)
「配列の配列」の各要素にメソッドを適用することはSelectでも可能ですが、結果がフラット(平坦)になる点が異なります。
List<List<int>> nums = new List<List<int>>()
{
new List<int>()
{
1, 2, 3
},
new List<int>()
{
4, 5, 6
},
new List<int>()
{
7, 8, 9
},
};
IEnumerable<int> selectMany =
nums.SelectMany(x => x.Select(y => y * 2));
//Selectメソッドのみの場合
IEnumerable<IEnumerable<int>> select =
nums.Select(x => x.Select(y => y * 2));
//通常のforeachでOK
foreach (var x in selectMany)
{
Console.Write("{0} ", x);
}
Console.WriteLine();
//こちらは二重のforeachが必要
foreach (var x in select)
{
foreach(var y in x)
Console.Write("{0} ", y);
}
2 4 6 8 10 12 14 16 18 2 4 6 8 10 12 14 16 18
Selectメソッドと同様に、要素番号を取得して利用することもできます。
IEnumerable<int> selectMany =
nums.SelectMany(
(x, index) => x.Where(
n => index > 1 && n % 2 == 0));
他のシーケンスと連携
SelectManyメソッドは基本的に対象のシーケンスに対して操作を行いますが、別のシーケンスを利用することもできます。
class Test
{
public int Num;
public List<string> Strs;
public Test(int n, List<string> s)
{
Num = n;
Strs = s;
}
}
static void Main(string[] args)
{
List<Test> tests = new List<Test>()
{
new Test(1, new List<string>() { "aaa", "bbb" }),
new Test(2, new List<string>() { "ccc", "ddd" }),
};
List<string> strs = new List<string>()
{
"aaa", "bbb", "ccc"
};
var selectMany1 = tests.SelectMany(
t => t.Strs,
(t, s) => new { Num = t.Num, Str = s });
//元のシーケンスに関係ないシーケンスを指定しても良い
var selectMany2 = tests.SelectMany(
t => strs,
(t, s) => new { Num = t.Num, Str = s });
foreach (var x in selectMany1)
Console.WriteLine("{0} {1}", x.Num, x.Str);
Console.WriteLine();
foreach (var x in selectMany2)
Console.WriteLine("{0} {1}", x.Num, x.Str);
}
1 aaa 1 bbb 2 ccc 2 ddd 1 aaa 1 bbb 1 ccc 2 aaa 2 bbb 2 ccc
SelectManyメソッドの第一引数に連携させたいシーケンスを指定します。
このラムダ式の引数には操作対象のシーケンスの要素が格納されるので、これを利用してシーケンスのメンバーにアクセスできます。
上記のコードでは要素が内部に持っているメンバー(フィールドStrs)を対象にしています。
元のシーケンスに関係のない外部のシーケンスを指定することもできます。
この場合はラムダ式の引数は使用しませんが、省略はできません。
第二引数には引数をふたつ持つメソッド(ラムダ式)を指定します。
このメソッドの第一引数は操作対象のシーケンスの要素が、第二引数には先ほど指定した連携させたいシーケンスの要素がそれぞれ格納されますので、それを利用してデータを加工します。
また、これも要素番号を取得して利用することもできます。
var selectMany = tests.SelectMany(
(t, index) => t.Strs.Where(s => index > 0),
(t, s) => new { Num = t.Num, Str = s });
GroupBy
GroupByメソッドは要素を指定のキーでグループ化します。
グループ化というのは指定のキーが共通する要素同士をまとめる(分類する)という意味です。
以下の例ではTestクラスのフィールドNumをキーとし、これが同じ値のインスタンスを同じグループとみなして分類しています。
戻り値は二次元配列のような構造で、foreach文のネスト(入れ子)で結果を表示します。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
IEnumerable<IGrouping<int, Test>> groupBy =
tests.GroupBy(x => x.Num);
foreach (var x in groupBy)
{
foreach (Test t in x)
Console.Write("{0}-{1} ", t.Num, t.Str);
Console.WriteLine();
}
1-aaa 1-ddd 2-bbb 3-ccc 3-eee
グループ化される要素の指定
第二引数でグループ化対象の要素を指定することもできます。
以下の例ではフィールドStrをグループ化される要素にしています。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
IEnumerable<IGrouping<int, string>> groupBy =
tests.GroupBy(x => x.Num, x => x.Str);
foreach (var x in groupBy)
{
Console.Write("{0} ", x.Key);
foreach (string s in x)
Console.Write("{0} ", s);
Console.WriteLine();
}
1 aaa ddd 2 bbb 3 ccc eee
戻り値の型がstring型(のシーケンス)になっていることに注目してください。
戻り値のデータ型の変換
上記のどちらの場合も、シーケンスに格納される値は「IGrouping<データ型1, データ型2>」という特殊な型(インターフェイス)です。
これを一般的な型(Listとか)に変換したい場合は、GroupByメソッドの第二引数のメソッドの引数を二つ指定します。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
IEnumerable<List<Test>> groupBy = tests.GroupBy(
x => x.Num,
(key, group) => group.ToList());
foreach (var x in groupBy)
{
foreach (Test t in x)
Console.Write("{0}-{1} ", t.Num, t.Str);
Console.WriteLine();
}
1-aaa 1-ddd 2-bbb 3-ccc 3-eee
このようにすると、メソッドの第一引数keyにはキーに指定した値が、第二引数groupにはkeyでグループ化されたシーケンス(IEnumerable)が渡されます。
このメソッドで返すデータ型によって、最終的に返されるシーケンスの型が変わります。
(IEnumerable<任意のデータ型>にできる)
そのままgroupを返すだけでも構いませんが、今回はToListでList化しています。
例えば匿名型で受け取る場合は以下のようになります。
ついでにIEnumerable型で返ってくる値もすべてList化しています。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
//匿名型なのでvar
//List<匿名型<int, List<Test>>>
var groupBy = tests.GroupBy(
x => x.Num,
(Key, group) => new { Key, Group = group.ToList() })
.ToList();
foreach (var x in groupBy)
{
Console.Write("{0} ", x.Key);
foreach (Test t in x.Group)
Console.Write("{0} ", t.Str);
Console.WriteLine();
}
Console.WriteLine();
//すべてListにしたので添え字でアクセスも可能
Console.WriteLine(groupBy[0].Group[0].Str);
1 aaa ddd 2 bbb 3 ccc eee aaa
グループ化される要素の指定+データ型の変換
グループ化対象の要素を指定しつつデータ型を変換する場合は、第一引数にキーを指定、第二引数にグループ化対象のデータを指定、第三引数に変換したいデータ型を返すメソッドを指定、という形式で行います。
List<Test> tests = new List<Test>()
{
new Test(1, "aaa"),
new Test(2, "bbb"),
new Test(3, "ccc"),
new Test(1, "ddd"),
new Test(3, "eee"),
};
//匿名型なのでvar
//IEnumerable<匿名型<int, IEnumerable<string>>>
var groupBy = tests.GroupBy(
x => x.Num,
x => x.Str,
(Key, Group) => new { Key, Group });
foreach (var x in groupBy)
{
Console.Write("{0} ", x.Key);
foreach (string s in x.Group)
Console.Write("{0} ", s);
Console.WriteLine();
}
1 aaa ddd 2 bbb 3 ccc eee
IEqualityComparer
GroupByメソッドのオーバーロードにはIEqualityComparerを引数に取るものがあります。
これはキーの比較の方法を指定したクラス(IEqualityComparerを継承したクラス)を指定します。
例えば文字列の大文字小文字を無視する、参照型をキーにする、などの場合に使用されます。
詳細はIEqualityComparerを参照してください。