C#のLINQメソッドは超便利!!、なんですが…肝心のAPIがわかりづらいです。
そこで、種類ごとにまとめて、簡単なサンプルを書いてみました。
- 結果の表示に、独自の拡張メソッド ToResult(this IEnumerable
) を使用しています。このメソッドは、本文の最後に記載しています。 - サンプルコードのダウンロードはこちら。
要素の取得(単一)
メソッド名 | 機能 |
---|---|
ElementAt ElementAtOrDefault |
指定した位置(インデックス)にある要素を返します。 |
First FirstOrDefault |
最初の要素を返します。 |
Last LastOrDefault |
最後の要素を返します。 |
Single SingleOrDefault |
唯一の要素を返します。該当する要素が複数ある場合、例外をスローします。 |
該当の要素がない場合は…
「〜OrDefault」が付いていないメソッドは例外をスローします。
「〜OrDefault」が付いたメソッドは型の規定値を返します。
var source = new[] { 10, 20, 30, 40 }; Console.WriteLine(source.ElementAt(1)); // -> 20 Console.WriteLine(source.ElementAtOrDefault(5)); // -> 0 Console.WriteLine(source.First()); // -> 10 Console.WriteLine(source.First(e => e > 15)); // -> 20 Console.WriteLine(source.Last()); // -> 40 Console.WriteLine(source.Last(e => e < 35)); // -> 30 try { Console.WriteLine(source.Single()); } catch(Exception e) { Console.WriteLine(e); } // -> System.InvalidOperationException: Sequence contains more than one element (シーケンスに複数の要素が含まれています) Console.WriteLine(source.Single(e => e > 35)); // -> 40
要素の取得(複数)
メソッド名 | 機能 |
---|---|
Where | 条件を満たす要素をすべて返します。 |
Distinct | 重複を除いたシーケンスを返します。 |
Skip | 先頭から指定された数の要素をスキップし、残りのシーケンスを返します。 |
SkipWhile | 先頭から指定された条件を満たさなくなるまで要素をスキップし、残りのシーケンスを返します。 |
Take | 先頭から指定された数の要素を返します。 |
TakeWhile | 先頭から指定された条件を満たす要素を返します。 |
var source = new[] { 10, 10, 20, 30, 40 }; Console.WriteLine(source.Where(e => e > 15).ToResult()); // -> {20, 30, 40} Console.WriteLine(source.Distinct().ToResult()); // -> {10, 20, 30, 40} Console.WriteLine(source.Skip(3).ToResult()); // -> {30, 40} Console.WriteLine(source.SkipWhile(e => e < 15).ToResult()); // -> {20, 30, 40} Console.WriteLine(source.Take(3).ToResult()); // -> {10, 20, 30} Console.WriteLine(source.TakeWhile(e => e < 15).ToResult()); // -> {10, 10}
集計
メソッド名 | 機能 |
---|---|
Max | 最大値を返します。 |
Min | 最小値を返します。 |
Average | 平均値を返します。 |
Sum | 合計を返します。 |
Count | 要素数を返します。 |
Aggregate | アキュムレータ関数で処理した結果を返します。 |
var source = new[] { 10, 20, 30, 40 }; Console.WriteLine(source.Max()); // -> 40 Console.WriteLine(source.Min()); // -> 10 Console.WriteLine(source.Average()); // -> 25 Console.WriteLine(source.Sum()); // -> 100 Console.WriteLine(source.Count()); // -> 4 Console.WriteLine(source.Aggregate((now, next) => now * next)); // -> 24000 // 参考:標本分散 double ave = source.Average(); Console.WriteLine(source.Sum(e => Math.Pow(e - ave, 2)) / source.Count()); // -> 125
判定
メソッド名 | 機能 |
---|---|
All | すべての要素が条件を満たしてるか判定します。 |
Any | 条件を満たす要素が含まれているか判定します。 |
Contains | 指定した要素が含まれているかどうかを判定します。 |
SequenceEqual | 2つのシーケンスが等しいかどうかを判定します。 |
var source = new[] { 10, 20, 30 }; Console.WriteLine(source.All(e => e > 15)); // -> False Console.WriteLine(source.Any(e => e > 15)); // -> True Console.WriteLine(source.Contains(20)); // -> True Console.WriteLine(source.SequenceEqual(new[] { 10, 20, 30 })); // -> True
集合
メソッド名 | 機能 |
---|---|
Union | 指定したシーケンスとの和集合を返します。 |
Except | 指定したシーケンスとの差集合を返します。 |
Intersect | 指定したシーケンスとの積集合を返します。 |
var first = new[] { 10, 20, 30, 40 }; var second = new[] { 60, 50, 40, 30 }; Console.WriteLine(first.Union(second).ToResult()); // -> {10, 20, 30, 40, 60, 50} Console.WriteLine(first.Except(second).ToResult()); // -> {10, 20} Console.WriteLine(first.Intersect(second).ToResult()); // -> {30, 40}
ソート
メソッド名 | 機能 |
---|---|
OrderBy | 昇順にソートしたシーケンスを返します。 |
OrderByDescending | 降順にソートしたシーケンスを返します。 |
ThenBy | ソートしたシーケンスに対し、キーが等しい要素同士を昇順にソートしたシーケンスを返します。 |
ThenByDescending | ソートしたシーケンスに対し、キーが等しい要素同士を降順にソートしたシーケンスを返します。 |
Reverse | 逆順にソートしたシーケンスを返します。 |
var source = new[] { new{Name = "A", Value = 20}, new{Name = "B", Value = 10}, new{Name = "C", Value = 20}, new{Name = "D", Value = 30}, }; Console.WriteLine(source.OrderBy(e => e.Value).ToResult()); // -> {{ Name = B, Value = 10 }, // { Name = A, Value = 20 }, // { Name = C, Value = 20 }, // { Name = D, Value = 30 }} Console.WriteLine(source.OrderByDescending(e => e.Value).ToResult()); // -> {{ Name = D, Value = 30 }, // { Name = A, Value = 20 }, // { Name = C, Value = 20 }, // { Name = B, Value = 10 }} Console.WriteLine(source.OrderBy(e => e.Value) .ThenBy(e => e.Name).ToResult()); // -> {{ Name = B, Value = 10 }, // { Name = A, Value = 20 }, // { Name = C, Value = 20 }, // { Name = D, Value = 30 }} Console.WriteLine(source.OrderBy(e => e.Value) .ThenByDescending(e => e.Name).ToResult()); // -> {{ Name = B, Value = 10 }, // { Name = C, Value = 20 }, // { Name = A, Value = 20 }, // { Name = D, Value = 30 }} Console.WriteLine(source.Reverse().ToResult()); // -> {{ Name = D, Value = 30 }, // { Name = C, Value = 20 }, // { Name = B, Value = 10 }, // { Name = A, Value = 20 }}
射影
メソッド名 | 機能 |
---|---|
Select | 1つの要素を単一の要素に射影します。 |
SelectMany | 1つの要素から複数の要素に射影します。その結果を1つのシーケンスとして返します。 |
GroupBy | 指定のキーで要素をグループ化します。その "キーとグループ" のシーケンスを返します。 |
var source = new[] { new{ Name = "A", Value = 20 }, new{ Name = "B", Value = 10 }, new{ Name = "C", Value = 20 }, new{ Name = "D", Value = 30 }, }; Console.WriteLine(source.Select(e => e.Name).ToResult()); // -> { A, B, C, D } Console.WriteLine(source.SelectMany(e => new object[] { e.Name, e.Value }).ToResult()); // -> { A, 20, B, 10, C, 20, D, 30 } Console.WriteLine(source.GroupBy(e => e.Value).ToResult()); // -> { Key = 20, Element = { { Name = A, Value = 20 }, { Name = C, Value = 20 } }, // Key = 10, Element = { { Name = B, Value = 10 } }, // Key = 30, Element = { { Name = D, Value = 30 } } }
結合
メソッド名 | 機能 |
---|---|
Join | 内部結合を行ったシーケンスを返します。 |
GroupJoin | 左外部結合を行って指定のキーでグループ化します。その "キーとグループ" のシーケンスを返します。 |
Concat | 2つのシーケンスを連結します。 (Unionは同じ要素を一つにまとめますが、Concatは元の要素をすべて返します。) |
DefaultIfEmpty | シーケンスを返します。シーケンスが空なら、規定値もしくは任意の要素を返します。 |
Zip | 指定した関数で、2つのシーケンスを1つのシーケンスにマージします。 |
var outer = new[] { new{ Name = "A", Value = 10 }, new{ Name = "B", Value = 20 }, new{ Name = "C", Value = 30 }, }; var inner = new[] { new{ Name = "X", Value = 20 }, new{ Name = "Y", Value = 30 }, new{ Name = "Z", Value = 30 } }; var empty = new int[0]; Console.WriteLine(outer.Join( inner, o => o.Value, i => i.Value, (o, i) => new { oName = o.Name, oValue = o.Value, iName = i.Name, iValue = i.Value } ).ToResult()); // -> {{ oName = B, oValue = 20, iName = X, iValue = 20 }, // { oName = C, oValue = 30, iName = Y, iValue = 30 }, // { oName = C, oValue = 30, iName = Z, iValue = 30 }} Console.WriteLine(outer.GroupJoin( inner, o => o.Value, i => i.Value, (o, i) => new { Name = o.Name, Value = o.Value, Group = i.Select( i => i.Name ).ToResult() } ).ToResult()); // -> {{ Name = A, Value = 10, Group = {} }, // { Name = B, Value = 20, Group = { X } }, // { Name = C, Value = 30, Group = { Y, Z } }} Console.WriteLine(outer.Concat(inner).ToResult()); // -> {{ Name = A, Value = 10 }, // { Name = B, Value = 20 }, // { Name = C, Value = 30 }, // { Name = X, Value = 20 }, // { Name = Y, Value = 30 }, // { Name = Z, Value = 30 }} Console.WriteLine(empty.DefaultIfEmpty().ToResult()); // -> { 0 } Console.WriteLine(outer.Zip(inner, (o, i) => o.Name + "&" + i.Name).ToResult()); // -> { A&X, B&Y, C&Z }
変換
メソッド名 | 機能 |
---|---|
OfType | 各要素を指定した型に変換します。 キャストできない要素は除外します。 |
Cast | 各要素を指定した型に変換します。 キャストできない要素が含まれていた場合、例外をスローします。 |
ToArray | 配列を作成します。 |
ToDictionary | 連想配列(ディクショナリ)を作成します。 |
ToList | リストを生成します。 |
ToLookup | キーコレクション*1を生成します。 |
AsEnumerable | IEnumerable |
var mixed = new object[] { "A", "B", 1, 2 }; var source = new[] { new{ Name = "A", Value = 20 }, new{ Name = "B", Value = 10 }, new{ Name = "C", Value = 20 }, new{ Name = "D", Value = 30 }, }; Console.WriteLine(mixed.OfType<string>().ToResult()); // -> { A, B } try { Console.WriteLine(mixed.Cast<string>().ToResult()); } catch (Exception e) { Console.WriteLine(e); } // -> System.InvalidCastException: 型 'System.Int32' のオブジェクトを型 'System.String' にキャストできません。 // (Unable to cast object of type 'System.Int32' to type 'System.String'.) Console.WriteLine(source.ToArray().ToResult()); // -> {{ Name = A, Value = 20 }, // { Name = B, Value = 10 }, // { Name = C, Value = 20 }, // { Name = D, Value = 30 }} Console.WriteLine(source.ToDictionary(x => x.Name, x => x.Value).ToResult()); // -> { [A, 20], [B, 10], [C, 20], [D, 30] } Console.WriteLine(source.ToLookup(x => x.Value, x => x.Name).ToResult()); // -> { Key = 20, Element = { A, C }, // Key = 10, Element = { B }, // Key = 30, Element = { D } }
補足 - 結果表示用の拡張メソッド
static String ToResult<TSource>(this IEnumerable<TSource> source) { return "{" + string.Join(", ", source) + "}"; } static String ToResult<TKey, TSource>(this IEnumerable<IGrouping<TKey, TSource>> source) { return source.Select(group => string.Format("Key={0}, Source={1}", group.Key, group.ToResult())).ToResult(); }