C# Language
LINQクエリ
サーチ…
前書き
LINQはtegrated Q ueryでIN Lの anguageの略頭字語です。これは、さまざまな種類のデータソースおよび形式にわたるデータを操作するための一貫したモデルを提供することによって、クエリ言語を統合する概念です。同じ基本コーディングパターンを使用して、XMLドキュメント、SQLデータベース、ADO.NETデータセット、.NETコレクション、およびLINQプロバイダが利用可能なその他の形式のデータをクエリおよび変換します。
構文
クエリ構文:
- <コレクション>の<範囲変数>から
- [from <range variable> in <collection>、...]
- <フィルタリング、結合、グループ化、集約演算子、...> <ラムダ式>
- <selectまたはgroupBy演算子> <結果を定式化する>
メソッドの構文:
- Enumerable.Aggregate(func)
- Enumerable.Aggregate(seed、func)
- Enumerable.Aggregate(seed、func、resultSelector)
- Enumerable.All(述語)
- Enumerable.Any()
- Enumerable.Any(述語)
- Enumerable.AsEnumerable()
- Enumerable.Average()
- Enumerable.Average(セレクタ)
- Enumerable.Cast <Result>()
- Enumerable.Concat(second)
- Enumerable.Contains(value)
- Enumerable.Contains(value、comparer)
- Enumerable.Count()
- Enumerable.Count(述語)
- Enumerable.DefaultIfEmpty()
- Enumerable.DefaultIfEmpty(defaultValue)
- Enumerable.Distinct()
- Enumerable.Distinct(comparer)
- Enumerable.ElementAt(index)
- Enumerable.ElementAtOrDefault(index)
- Enumerable.Empty()
- Enumerable.Except(秒)
- Enumerable.Except(second、comparer)
- Enumerable.First()
- Enumerable.First(述語)
- Enumerable.FirstOrDefault()
- Enumerable.FirstOrDefault(述語)
- Enumerable.GroupBy(keySelector)
- Enumerable.GroupBy(keySelector、resultSelector)
- Enumerable.GroupBy(keySelector、elementSelector)
- Enumerable.GroupBy(keySelector、comparer)
- Enumerable.GroupBy(keySelector、resultSelector、comparer)
- Enumerable.GroupBy(keySelector、elementSelector、resultSelector)
- Enumerable.GroupBy(keySelector、elementSelector、comparer)
- Enumerable.GroupBy(keySelector、elementSelector、resultSelector、comparer)
- Enumerable.Intersect(秒)
- Enumerable.Intersect(second、comparer)
- Enumerable.Join(inner、outerKeySelector、innerKeySelector、resultSelector)
- Enumerable.Join(inner、outerKeySelector、innerKeySelector、resultSelector、comparer)
- Enumerable.Last()
- Enumerable.Last(述語)
- Enumerable.LastOrDefault()
- Enumerable.LastOrDefault(述語)
- Enumerable.LongCount()
- Enumerable.LongCount(述語)
- Enumerable.Max()
- Enumerable.Max(セレクタ)
- Enumerable.Min()
- Enumerable.Min(セレクタ)
- Enumerable.OfType <TResult>()
- Enumerable.OrderBy(keySelector)
- Enumerable.OrderBy(keySelector、comparer)
- Enumerable.OrderByDescending(keySelector)
- Enumerable.OrderByDescending(keySelector、comparer)
- Enumerable.Range(開始、カウント)
- Enumerable.Repeat(要素、カウント)
- Enumerable.Reverse()
- Enumerable.Select(セレクタ)
- Enumerable.SelectMany(セレクタ)
- Enumerable.SelectMany(collectionSelector、resultSelector)
- Enumerable.SequenceEqual(second)
- Enumerable.SequenceEqual(second、comparer)
- Enumerable.Single()
- Enumerable.Single(述語)
- Enumerable.SingleOrDefault()
- Enumerable.SingleOrDefault(述語)
- Enumerable.Skip(count)
- Enumerable.SkipWhile(述語)
- Enumerable.Sum()
- Enumerable.Sum(セレクタ)
- Enumerable.Take(count)
- Enumerable.TakeWhile(述語)
- orderedEnumerable.ThenBy(keySelector)
- orderedEnumerable.ThenBy(keySelector、comparer)
- orderedEnumerable.ThenByDescending(keySelector)
- orderedEnumerable.ThenByDescending(keySelector、comparer)
- Enumerable.ToArray()
- Enumerable.ToDictionary(keySelector)
- Enumerable.ToDictionary(keySelector、elementSelector)
- Enumerable.ToDictionary(keySelector、comparer)
- Enumerable.ToDictionary(keySelector、elementSelector、comparer)
- Enumerable.ToList()
- Enumerable.ToLookup(keySelector)
- Enumerable.ToLookup(keySelector、elementSelector)
- Enumerable.ToLookup(keySelector、comparer)
- Enumerable.ToLookup(keySelector、elementSelector、comparer)
- Enumerable.Union(秒)
- Enumerable.Union(second、comparer)
- Enumerable.Where(述語)
- Enumerable.Zip(second、resultSelector)
備考
LINQクエリを使用するには、 System.Linq
をインポートする必要があります。
Method Syntaxはより強力で柔軟性がありますが、Query Syntaxはよりシンプルで使い慣れたものになります。 Query構文で記述されたすべてのクエリは、コンパイラによって機能構文に変換されるため、パフォーマンスは同じです。
照会オブジェクトは、使用されるまで評価されないため、パフォーマンスの低下なしに変更または追加することができます。
どこで
指定された述語が真である項目のサブセットを返します。
List<string> trees = new List<string>{ "Oak", "Birch", "Beech", "Elm", "Hazel", "Maple" };
メソッド構文
// Select all trees with name of length 3
var shortTrees = trees.Where(tree => tree.Length == 3); // Oak, Elm
クエリ構文
var shortTrees = from tree in trees
where tree.Length == 3
select tree; // Oak, Elm
選択 - 要素の変形
Selectを使用すると、IEnumerableを実装しているすべてのデータ構造のすべての要素に変換を適用できます。
次のリストの各文字列の最初の文字を取得します。
List<String> trees = new List<String>{ "Oak", "Birch", "Beech", "Elm", "Hazel", "Maple" };
正規(ラムダ)構文の使用
//The below select stament transforms each element in tree into its first character.
IEnumerable<String> initials = trees.Select(tree => tree.Substring(0, 1));
foreach (String initial in initials) {
System.Console.WriteLine(initial);
}
出力:
O
B
B
E
H
M
LINQクエリ構文の使用
initials = from tree in trees
select tree.Substring(0, 1);
メソッドの連鎖
多くのLINQ関数はIEnumerable<TSource>
動作し、 IEnumerable<TResult>
も返します。型パラメータTSource
とTResult
は、問題のメソッドとそれに渡された関数に応じて、同じ型を参照する場合と参照しない場合があります。
これのいくつかの例があります
public static IEnumerable<TResult> Select<TSource, TResult>(
this IEnumerable<TSource> source,
Func<TSource, TResult> selector
)
public static IEnumerable<TSource> Where<TSource>(
this IEnumerable<TSource> source,
Func<TSource, int, bool> predicate
)
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(
this IEnumerable<TSource> source,
Func<TSource, TKey> keySelector
)
一部のメソッドチェーニングでは、移動する前にセット全体を処理する必要がありますが、LINQは、舞台裏でEnumerableとEnumeratorを作成するyield return MSDNを使用して、 遅延実行を利用します。 LINQで連鎖するプロセスは、本質的に、列挙可能なものを列挙することによって実現されるまで、元のセットのための列挙可能な(イテレータ)を構築しています。
これにより、これらの関数を流暢に連鎖させることができます 。ここでは、ある関数が別の関数の結果に直接作用することができます。このスタイルのコードは、1つのステートメントで多くのシーケンスベースの操作を実行するために使用できます。
たとえば、 Select
、 Where
、およびOrderBy
を組み合わせて、1つのステートメントでシーケンスを変換、フィルタリング、ソートすることができます。
var someNumbers = { 4, 3, 2, 1 };
var processed = someNumbers
.Select(n => n * 2) // Multiply each number by 2
.Where(n => n != 6) // Keep all the results, except for 6
.OrderBy(n => n); // Sort in ascending order
出力:
2
4
8
一般的なIEnumerable<T>
型を拡張して返す関数はすべて、単一のステートメントで連鎖句として使用できます。この流暢なプログラミングスタイルは強力で、独自の拡張メソッドを作成するときには考慮する必要があります。
範囲と繰り返し
Enumerable
のRange
とRepeat
静的メソッドは、単純なシーケンスを生成するために使用できEnumerable
。
範囲
Enumerable.Range()
は、開始値とカウントが与えられた整数のシーケンスを生成します。
// Generate a collection containing the numbers 1-100 ([1, 2, 3, ..., 98, 99, 100])
var range = Enumerable.Range(1,100);
繰り返す
Enumerable.Repeat()
は、要素と必要な繰り返し回数を指定して繰り返し要素のシーケンスを生成しEnumerable.Repeat()
。
// Generate a collection containing "a", three times (["a","a","a"])
var repeatedValues = Enumerable.Repeat("a", 3);
スキップ&テイク
Skipメソッドは、ソースコレクションの先頭からいくつかの項目を除いたコレクションを返します。除外される項目の数は、引数として与えられた数です。引数に指定された数より少ない数の項目がコレクション内にある場合、空のコレクションが返されます。
Takeメソッドは、ソースコレクションの先頭からいくつかの要素を含むコレクションを返します。含まれる項目の数は引数として与えられた数です。引数に指定された数より少ない数の項目がコレクション内にある場合、戻されるコレクションにはソース・コレクションと同じ要素が含まれます。
var values = new [] { 5, 4, 3, 2, 1 };
var skipTwo = values.Skip(2); // { 3, 2, 1 }
var takeThree = values.Take(3); // { 5, 4, 3 }
var skipOneTakeTwo = values.Skip(1).Take(2); // { 4, 3 }
var takeZero = values.Take(0); // An IEnumerable<int> with 0 items
SkipとTakeは、結果のページ付けを行うために一般的に一緒に使用されます。
IEnumerable<T> GetPage<T>(IEnumerable<T> collection, int pageNumber, int resultsPerPage) {
int startIndex = (pageNumber - 1) * resultsPerPage;
return collection.Skip(startIndex).Take(resultsPerPage);
}
警告: LINQ to Entitiesは、 順序付けされたクエリのスキップしかサポートしていません。あなたがメッセージで非サポート例外を取得します注文せずにスキップ使用しようとすると、「方法『をスキップ』はエンティティへのLINQでソートされた入力のためにサポートされています。方法『のOrderBy』メソッドの前に呼び出されなければならない『スキップ』。」
最初に、FirstOrDefault、Last、LastOrDefault、Single、およびSingleOrDefault
6つのメソッドはすべて、シーケンス型の単一の値を返し、述語の有無にかかわらず呼び出すことができます。
predicate
と一致する要素の数、またはpredicate
が指定されていない場合は、ソースシーケンスの要素数に応じて、次のように動作します。
最初()
- シーケンスの最初の要素、または指定された
predicate
一致する最初の要素を返します。 - シーケンスに要素が含まれていない場合は、「シーケンスに要素がありません」というメッセージとともに
InvalidOperationException
がスローされます。 - シーケンスに指定された
predicate
と一致する要素が含まれていない場合、InvalidOperationException
がスローされ、「シーケンスに一致する要素が含まれていません」というメッセージが表示されます。
例
// Returns "a":
new[] { "a" }.First();
// Returns "a":
new[] { "a", "b" }.First();
// Returns "b":
new[] { "a", "b" }.First(x => x.Equals("b"));
// Returns "ba":
new[] { "ba", "be" }.First(x => x.Contains("b"));
// Throws InvalidOperationException:
new[] { "ca", "ce" }.First(x => x.Contains("b"));
// Throws InvalidOperationException:
new string[0].First();
FirstOrDefault()
- シーケンスの最初の要素、または指定された
predicate
一致する最初の要素を返します。 - シーケンスに要素が含まれていない場合、または提供された
predicate
に一致する要素がない場合は、default(T)
を使用してシーケンス・タイプのデフォルト値を戻します。
例
// Returns "a":
new[] { "a" }.FirstOrDefault();
// Returns "a":
new[] { "a", "b" }.FirstOrDefault();
// Returns "b":
new[] { "a", "b" }.FirstOrDefault(x => x.Equals("b"));
// Returns "ba":
new[] { "ba", "be" }.FirstOrDefault(x => x.Contains("b"));
// Returns null:
new[] { "ca", "ce" }.FirstOrDefault(x => x.Contains("b"));
// Returns null:
new string[0].FirstOrDefault();
最終()
- シーケンスの最後の要素、または指定された
predicate
一致する最後の要素を返します。 - シーケンスに要素が含まれていない場合は、「シーケンスに要素がありません」というメッセージとともに
InvalidOperationException
がスローされます。 - シーケンスに指定された
predicate
と一致する要素が含まれていない場合、InvalidOperationException
がスローされ、「シーケンスに一致する要素が含まれていません」というメッセージが表示されます。
例
// Returns "a":
new[] { "a" }.Last();
// Returns "b":
new[] { "a", "b" }.Last();
// Returns "a":
new[] { "a", "b" }.Last(x => x.Equals("a"));
// Returns "be":
new[] { "ba", "be" }.Last(x => x.Contains("b"));
// Throws InvalidOperationException:
new[] { "ca", "ce" }.Last(x => x.Contains("b"));
// Throws InvalidOperationException:
new string[0].Last();
LastOrDefault()
- シーケンスの最後の要素、または指定された
predicate
一致する最後の要素を返します。 - シーケンスに要素が含まれていない場合、または提供された
predicate
に一致する要素がない場合は、default(T)
を使用してシーケンス・タイプのデフォルト値を戻します。
例
// Returns "a":
new[] { "a" }.LastOrDefault();
// Returns "b":
new[] { "a", "b" }.LastOrDefault();
// Returns "a":
new[] { "a", "b" }.LastOrDefault(x => x.Equals("a"));
// Returns "be":
new[] { "ba", "be" }.LastOrDefault(x => x.Contains("b"));
// Returns null:
new[] { "ca", "ce" }.LastOrDefault(x => x.Contains("b"));
// Returns null:
new string[0].LastOrDefault();
シングル()
- シーケンスに厳密に1つの要素が含まれている場合、または指定された
predicate
と一致する要素が1つだけ含まれている場合、その要素が戻されます。 - シーケンスに要素が含まれていない場合、または提供された
predicate
に一致する要素がない場合は、「シーケンスに要素が含まれていません」というメッセージとともにInvalidOperationException
がスローされます。 - シーケンスに複数の要素が含まれている場合、または複数の要素が指定された
predicate
と一致する場合は、「シーケンスに複数の要素が含まれています」というメッセージとともにInvalidOperationException
がスローされます。 - 注:シーケンスに厳密に1つの要素が含まれているかどうかを評価するために、最大で2つの要素を列挙する必要があります。
例
// Returns "a":
new[] { "a" }.Single();
// Throws InvalidOperationException because sequence contains more than one element:
new[] { "a", "b" }.Single();
// Returns "b":
new[] { "a", "b" }.Single(x => x.Equals("b"));
// Throws InvalidOperationException:
new[] { "a", "b" }.Single(x => x.Equals("c"));
// Throws InvalidOperationException:
new string[0].Single();
// Throws InvalidOperationException because sequence contains more than one element:
new[] { "a", "a" }.Single();
SingleOrDefault()
- シーケンスに厳密に1つの要素が含まれている場合、または指定された
predicate
と一致する要素が1つだけ含まれている場合、その要素が戻されます。 - シーケンスに要素が含まれていない場合、または提供された
predicate
と一致する要素がない場合は、default(T)
が戻されます。 - シーケンスに複数の要素が含まれている場合、または複数の要素が指定された
predicate
と一致する場合は、「シーケンスに複数の要素が含まれています」というメッセージとともにInvalidOperationException
がスローされます。 - シーケンスに、提供された
predicate
と一致する要素が含まれていない場合は、default(T)
を使用してシーケンス・タイプのデフォルト値を戻します。 - 注:シーケンスに厳密に1つの要素が含まれているかどうかを評価するために、最大で2つの要素を列挙する必要があります。
例
// Returns "a":
new[] { "a" }.SingleOrDefault();
// returns "a"
new[] { "a", "b" }.SingleOrDefault(x => x == "a");
// Returns null:
new[] { "a", "b" }.SingleOrDefault(x => x == "c");
// Throws InvalidOperationException:
new[] { "a", "a" }.SingleOrDefault(x => x == "a");
// Throws InvalidOperationException:
new[] { "a", "b" }.SingleOrDefault();
// Returns null:
new string[0].SingleOrDefault();
推奨事項
FirstOrDefault
、LastOrDefault
またはSingleOrDefault
を使用してシーケンスに項目が含まれているかどうかを確認できますが、Any
またはCount
方が信頼性が高くなります。これは、シーケンスの最初/最後/単一要素のdefault(T)
が同じようにdefault(T)
になる可能性があるため、これらの3つのメソッドのいずれかからのdefault(T)
戻り値がシーケンスが空であることを証明しないためdefault(T)
コードの目的に最も適した方法を決定します。例えば、使用
Single
あなたの述語に一致するコレクション内の単一の項目があることを確認する必要がある場合のみ-それ以外の使用First
、シーケンスに複数の要素が一致する場合、Single
は例外をスローします。もちろんこれは "* OrDefault" - 同じ部分にも当てはまります。効率性について:1つのアイテム(
Single
)、または1つまたはゼロ(SingleOrDefault
)のアイテムのみがクエリによって返されることを保証することはしばしば適切ですが、これらのメソッドは両方ともコレクションのより多くの、しばしば全体を必要としますクエリに2番目の一致がないことを確認します。これは、例えば、最初のマッチを見つけた後に満足できるFirst
メソッドの動作とは異なります。
例外
Exceptメソッドは、最初のコレクションに含まれているが2番目のコレクションに含まれていないアイテムのセットを返します。デフォルトのIEqualityComparer
は、2つのセット内の項目を比較するために使用されます。 IEqualityComparer
を引数として受け入れるオーバーロードがあります。
例:
int[] first = { 1, 2, 3, 4 };
int[] second = { 0, 2, 3, 5 };
IEnumerable<int> inFirstButNotInSecond = first.Except(second);
// inFirstButNotInSecond = { 1, 4 }
出力:
1
4
この場合.Except(second)
の配列に含まれる要素を除外second
、すなわち2及び3(0および5はに含まれていないfirst
のアレイおよびスキップされます)。
Except
Distinct
意味します(つまり、繰り返し要素を削除します)。例えば:
int[] third = { 1, 1, 1, 2, 3, 4 };
IEnumerable<int> inThirdButNotInSecond = third.Except(second);
// inThirdButNotInSecond = { 1, 4 }
出力:
1
4
この場合、要素1と要素4は1回だけ返されます。
IEquatable
実装IEquatable
か、 IEqualityComparer
関数を使用すると、異なるメソッドを使用して要素を比較できます。 GetHashCode
メソッドもオーバーライドして、 IEquatable
実装に従って同一のobject
用の同一のハッシュコードを返すようにする必要があることに注意してください。
IEquatableを使用した例:
class Holiday : IEquatable<Holiday>
{
public string Name { get; set; }
public bool Equals(Holiday other)
{
return Name == other.Name;
}
// GetHashCode must return true whenever Equals returns true.
public override int GetHashCode()
{
//Get hash code for the Name field if it is not null.
return Name?.GetHashCode() ?? 0;
}
}
public class Program
{
public static void Main()
{
List<Holiday> holidayDifference = new List<Holiday>();
List<Holiday> remoteHolidays = new List<Holiday>
{
new Holiday { Name = "Xmas" },
new Holiday { Name = "Hanukkah" },
new Holiday { Name = "Ramadan" }
};
List<Holiday> localHolidays = new List<Holiday>
{
new Holiday { Name = "Xmas" },
new Holiday { Name = "Ramadan" }
};
holidayDifference = remoteHolidays
.Except(localHolidays)
.ToList();
holidayDifference.ForEach(x => Console.WriteLine(x.Name));
}
}
出力:
ハヌカ
SelectMany:シーケンスのシーケンスを平坦化する
var sequenceOfSequences = new [] { new [] { 1, 2, 3 }, new [] { 4, 5 }, new [] { 6 } };
var sequence = sequenceOfSequences.SelectMany(x => x);
// returns { 1, 2, 3, 4, 5, 6 }
SelectMany()
使用するか、シーケンスのシーケンスを作成していますが、その結果を1つの長いシーケンスとしたい場合に使用します。
LINQクエリ構文:
var sequence = from subSequence in sequenceOfSequences
from item in subSequence
select item;
コレクションのコレクションがあり、同時に親コレクションと子コレクションのデータを処理できるようにしたい場合は、 SelectMany
でも可能です。
簡単なクラスを定義しましょう
public class BlogPost
{
public int Id { get; set; }
public string Content { get; set; }
public List<Comment> Comments { get; set; }
}
public class Comment
{
public int Id { get; set; }
public string Content { get; set; }
}
以下のコレクションがあるとしましょう。
List<BlogPost> posts = new List<BlogPost>()
{
new BlogPost()
{
Id = 1,
Comments = new List<Comment>()
{
new Comment()
{
Id = 1,
Content = "It's really great!",
},
new Comment()
{
Id = 2,
Content = "Cool post!"
}
}
},
new BlogPost()
{
Id = 2,
Comments = new List<Comment>()
{
new Comment()
{
Id = 3,
Content = "I don't think you're right",
},
new Comment()
{
Id = 4,
Content = "This post is a complete nonsense"
}
}
}
};
このコメントに関連付けられているBlogPost
Id
とともにコメントのContent
を選択します。そうするために、適切なSelectMany
オーバーロードを使用することができます。
var commentsWithIds = posts.SelectMany(p => p.Comments, (post, comment) => new { PostId = post.Id, CommentContent = comment.Content });
私たちのcommentsWithIds
は次のようになります
{
PostId = 1,
CommentContent = "It's really great!"
},
{
PostId = 1,
CommentContent = "Cool post!"
},
{
PostId = 2,
CommentContent = "I don't think you're right"
},
{
PostId = 2,
CommentContent = "This post is a complete nonsense"
}
SelectMany
SelectMany linqメソッドは、 IEnumerable<IEnumerable<T>>
をIEnumerable<T>
'平坦化'します。ソースIEnumerable
含まれるIEnumerable
インスタンス内のT要素はすべて、単一のIEnumerable
結合されます。
var words = new [] { "a,b,c", "d,e", "f" };
var splitAndCombine = words.SelectMany(x => x.Split(','));
// returns { "a", "b", "c", "d", "e", "f" }
入力要素をシーケンスに変換するセレクタ関数を使用すると、結果はそれらのシーケンスの要素が1つずつ返されます。
Select()
とは異なり、出力の要素の数は入力の要素の数と同じである必要はありません。
より現実的な例
class School
{
public Student[] Students { get; set; }
}
class Student
{
public string Name { get; set; }
}
var schools = new [] {
new School(){ Students = new [] { new Student { Name="Bob"}, new Student { Name="Jack"} }},
new School(){ Students = new [] { new Student { Name="Jim"}, new Student { Name="John"} }}
};
var allStudents = schools.SelectMany(s=> s.Students);
foreach(var student in allStudents)
{
Console.WriteLine(student.Name);
}
出力:
ボブ
ジャック
ジム
ジョン
すべて
All
は、コレクションのすべての要素が条件に一致するかどうかをチェックするために使用されます。
以下を参照してください: .Any
1.空のパラメータ
All :空のパラメータでは使用できません。
2.パラメータとしてのラムダ式
All :コレクションのすべての要素がラムダ式を満たす場合はtrue
返し、そうでない場合はfalse
返します。
var numbers = new List<int>(){ 1, 2, 3, 4, 5};
bool result = numbers.All(i => i < 10); // true
bool result = numbers.All(i => i >= 3); // false
3.空のコレクション
すべて :コレクションが空でラムダ式が指定されている場合はtrue
返します。
var numbers = new List<int>();
bool result = numbers.All(i => i >= 0); // true
注: All
は、条件と一致しない要素を見つけるとすぐにコレクションの反復を停止します。つまり、コレクションが必ずしも完全に列挙されるわけではありません。条件に一致しない最初の項目を見つけるために十分に列挙されます。
タイプ別にクエリを収集する/タイプするキャストエレメント
interface IFoo { }
class Foo : IFoo { }
class Bar : IFoo { }
var item0 = new Foo();
var item1 = new Foo();
var item2 = new Bar();
var item3 = new Bar();
var collection = new IFoo[] { item0, item1, item2, item3 };
OfType
使用
var foos = collection.OfType<Foo>(); // result: IEnumerable<Foo> with item0 and item1
var bars = collection.OfType<Bar>(); // result: IEnumerable<Bar> item item2 and item3
var foosAndBars = collection.OfType<IFoo>(); // result: IEnumerable<IFoo> with all four items
Where
使う
var foos = collection.Where(item => item is Foo); // result: IEnumerable<IFoo> with item0 and item1
var bars = collection.Where(item => item is Bar); // result: IEnumerable<IFoo> with item2 and item3
Cast
を使用する
var bars = collection.Cast<Bar>(); // throws InvalidCastException on the 1st item
var foos = collection.Cast<Foo>(); // throws InvalidCastException on the 3rd item
var foosAndBars = collection.Cast<IFoo>(); // OK
連合
2つのコレクションを結合して、デフォルトの等価比較元を使用して異なるコレクションを作成します。
int[] numbers1 = { 1, 2, 3 };
int[] numbers2 = { 2, 3, 4, 5 };
var allElement = numbers1.Union(numbers2); // AllElement now contains 1,2,3,4,5
ジョイン
結合は、共通のキーを介してデータを保持する異なるリストまたはテーブルを結合するために使用されます。
LINQでは、SQLと同様に、次の種類の結合がサポートされています。
内、左、右、十字 、 完全外結合。
次の2つのリストは、以下の例で使用されています。
var first = new List<string>(){ "a","b","c"}; // Left data
var second = new List<string>(){ "a", "c", "d"}; // Right data
(内部)結合
var result = from f in first
join s in second on f equals s
select new { f, s };
var result = first.Join(second,
f => f,
s => s,
(f, s) => new { f, s });
// Result: {"a","a"}
// {"c","c"}
左外部結合
var leftOuterJoin = from f in first
join s in second on f equals s into temp
from t in temp.DefaultIfEmpty()
select new { First = f, Second = t};
// Or can also do:
var leftOuterJoin = from f in first
from s in second.Where(x => x == f).DefaultIfEmpty()
select new { First = f, Second = s};
// Result: {"a","a"}
// {"b", null}
// {"c","c"}
// Left outer join method syntax
var leftOuterJoinFluentSyntax = first.GroupJoin(second,
f => f,
s => s,
(f, s) => new { First = f, Second = s })
.SelectMany(temp => temp.Second.DefaultIfEmpty(),
(f, s) => new { First = f.First, Second = s });
右外部結合
var rightOuterJoin = from s in second
join f in first on s equals f into temp
from t in temp.DefaultIfEmpty()
select new {First=t,Second=s};
// Result: {"a","a"}
// {"c","c"}
// {null,"d"}
クロス結合
var CrossJoin = from f in first
from s in second
select new { f, s };
// Result: {"a","a"}
// {"a","c"}
// {"a","d"}
// {"b","a"}
// {"b","c"}
// {"b","d"}
// {"c","a"}
// {"c","c"}
// {"c","d"}
完全な外部結合
var fullOuterjoin = leftOuterJoin.Union(rightOuterJoin);
// Result: {"a","a"}
// {"b", null}
// {"c","c"}
// {null,"d"}
実際の例
上記の例は単純なデータ構造を持っているため、技術的に異なるLINQ結合の理解に集中することができますが、現実世界では、参加する必要がある列を持つテーブルがあります。
次の例では、実際には1つのクラスRegion
しか使用されていませんが、同じキーを保持する2つ以上の異なるテーブルを結合します(この例では、 first
とsecond
は共通キーID
結合されていID
)。
例:次のデータ構造を考えてみましょう。
public class Region
{
public Int32 ID;
public string RegionDescription;
public Region(Int32 pRegionID, string pRegionDescription=null)
{
ID = pRegionID; RegionDescription = pRegionDescription;
}
}
データを準備します(つまり、データを取り込みます)。
// Left data
var first = new List<Region>()
{ new Region(1), new Region(3), new Region(4) };
// Right data
var second = new List<Region>()
{
new Region(1, "Eastern"), new Region(2, "Western"),
new Region(3, "Northern"), new Region(4, "Southern")
};
この例では、 first
領域の説明が含まれていないので、 second
領域の記述に参加したいことがわかります。次に、内部結合は次のようになります。
// do the inner join
var result = from f in first
join s in second on f.ID equals s.ID
select new { f.ID, s.RegionDescription };
// Result: {1,"Eastern"}
// {3, Northern}
// {4,"Southern"}
この結果、匿名のオブジェクトが作成されましたが、これは問題ありませんが、すでに適切なクラスを作成しています。これを指定することができます: select new { f.ID, s.RegionDescription };
select new Region(f.ID, s.RegionDescription);
と言うことができselect new Region(f.ID, s.RegionDescription);
同じデータを返しますが、他のオブジェクトとの互換性を維持するRegion
型のオブジェクトを作成します。
独特な
IEnumerable
から一意の値を返します。一意性は、デフォルトの等価比較子を使用して決定されます。
int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };
var distinct = array.Distinct();
// distinct = { 1, 2, 3, 4, 5 }
カスタムデータ型を比較するには、 IEquatable<T>
インターフェイスを実装し、 GetHashCode
メソッドとEquals
メソッドを提供する必要があります。または、等価比較演算子をオーバーライドすることもできます。
class SSNEqualityComparer : IEqualityComparer<Person> {
public bool Equals(Person a, Person b) => return a.SSN == b.SSN;
public int GetHashCode(Person p) => p.SSN;
}
List<Person> people;
distinct = people.Distinct(SSNEqualityComparer);
グループ1つまたは複数のフィールド
我々はいくつかのフィルムモデルを持っていると仮定します:
public class Film {
public string Title { get; set; }
public string Category { get; set; }
public int Year { get; set; }
}
カテゴリ別のプロパティ:
foreach (var grp in films.GroupBy(f => f.Category)) {
var groupCategory = grp.Key;
var numberOfFilmsInCategory = grp.Count();
}
カテゴリと年別のグループ:
foreach (var grp in films.GroupBy(f => new { Category = f.Category, Year = f.Year })) {
var groupCategory = grp.Key.Category;
var groupYear = grp.Key.Year;
var numberOfFilmsInCategory = grp.Count();
}
さまざまなLinqメソッドでRangeを使う
Linqクエリと並んでEnumerableクラスを使用して、ループをLinqの1つのライナーに変換できます。
選択例
これに反対する:
var asciiCharacters = new List<char>();
for (var x = 0; x < 256; x++)
{
asciiCharacters.Add((char)x);
}
あなたはこれを行うことができます:
var asciiCharacters = Enumerable.Range(0, 256).Select(a => (char) a);
例
この例では、100個の数字が生成され、それらも抽出されます
var evenNumbers = Enumerable.Range(1, 100).Where(a => a % 2 == 0);
クエリの順序付け - OrderBy()ThenBy()OrderByDescending()ThenByDescending()
string[] names= { "mark", "steve", "adam" };
上昇:
クエリの構文
var sortedNames =
from name in names
orderby name
select name;
メソッドの構文
var sortedNames = names.OrderBy(name => name);
sortedNamesには、「adam」、「mark」、「steve」の順に名前が含まれています。
降順:
クエリの構文
var sortedNames =
from name in names
orderby name descending
select name;
メソッドの構文
var sortedNames = names.OrderByDescending(name => name);
sortedNamesには、 "steve"、 "mark"、 "adam"
複数のフィールドで注文する
Person[] people =
{
new Person { FirstName = "Steve", LastName = "Collins", Age = 30},
new Person { FirstName = "Phil" , LastName = "Collins", Age = 28},
new Person { FirstName = "Adam" , LastName = "Ackerman", Age = 29},
new Person { FirstName = "Adam" , LastName = "Ackerman", Age = 15}
};
クエリの構文
var sortedPeople = from person in people
orderby person.LastName, person.FirstName, person.Age descending
select person;
メソッドの構文
sortedPeople = people.OrderBy(person => person.LastName)
.ThenBy(person => person.FirstName)
.ThenByDescending(person => person.Age);
結果
1. Adam Ackerman 29
2. Adam Ackerman 15
3. Phil Collins 28
4. Steve Collins 30
基本
LINQは、コレクション(または配列)を照会するのに大いに有益です。
たとえば、次のサンプルデータがあるとします。
var classroom = new Classroom
{
new Student { Name = "Alice", Grade = 97, HasSnack = true },
new Student { Name = "Bob", Grade = 82, HasSnack = false },
new Student { Name = "Jimmy", Grade = 71, HasSnack = true },
new Student { Name = "Greg", Grade = 90, HasSnack = false },
new Student { Name = "Joe", Grade = 59, HasSnack = false }
}
LINQ構文を使用してこのデータを「照会」することができます。たとえば、今日スナックを持っているすべての学生を検索するには:
var studentsWithSnacks = from s in classroom.Students
where s.HasSnack
select s;
または、90以上の学年の学生を取得し、完全なStudent
オブジェクトではなく、名前のみを返す:
var topStudentNames = from s in classroom.Students
where s.Grade >= 90
select s.Name;
LINQ機能は、同じ機能を実行する2つの構文で構成され、ほぼ同じパフォーマンスを持ちますが、非常に異なった書き方をしています。上記の例の構文は、 クエリ構文と呼ばれます 。ただし、次の例では、 メソッドの構文を示しています 。上記の例と同じデータが返されますが、クエリが書き込まれる方法は異なります。
var topStudentNames = classroom.Students
.Where(s => s.Grade >= 90)
.Select(s => s.Name);
GroupBy
GroupByは、項目のIEnumerable<T>
コレクションを異なるグループに分類する簡単な方法です。
簡単な例
この最初の例では、奇数と偶数の2つのグループになります。
List<int> iList = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var grouped = iList.GroupBy(x => x % 2 == 0);
//Groups iList into odd [13579] and even[2468] items
foreach(var group in grouped)
{
foreach (int item in group)
{
Console.Write(item); // 135792468 (first odd then even)
}
}
より複雑な例
例として年齢別に人のリストをグループ化しましょう。まず、名前と年齢の2つのプロパティを持つPersonオブジェクトを作成します。
public class Person
{
public int Age {get; set;}
public string Name {get; set;}
}
次に、様々な名前と年齢の人のサンプルリストを作成します。
List<Person> people = new List<Person>();
people.Add(new Person{Age = 20, Name = "Mouse"});
people.Add(new Person{Age = 30, Name = "Neo"});
people.Add(new Person{Age = 40, Name = "Morpheus"});
people.Add(new Person{Age = 30, Name = "Trinity"});
people.Add(new Person{Age = 40, Name = "Dozer"});
people.Add(new Person{Age = 40, Name = "Smith"});
次に、LINQクエリを作成して、人のリストを年齢順にグループ化します。
var query = people.GroupBy(x => x.Age);
そうすることで、各グループの年齢を確認し、グループ内の各人のリストを見ることができます。
foreach(var result in query)
{
Console.WriteLine(result.Key);
foreach(var person in result)
Console.WriteLine(person.Name);
}
これにより、次のような結果が得られます。
20
Mouse
30
Neo
Trinity
40
Morpheus
Dozer
Smith
.NET Fiddleのライブデモで遊ぶことができます
どれか
Any
は、コレクションの要素が条件に一致するかどうかをチェックするために使用されます。
.All 、 Any、FirstOrDefault:ベストプラクティスも参照してください。
1.空のパラメータ
Any :コレクションに要素がtrue
場合はtrue
返し、コレクションが空の場合はfalse
返します。
var numbers = new List<int>();
bool result = numbers.Any(); // false
var numbers = new List<int>(){ 1, 2, 3, 4, 5};
bool result = numbers.Any(); //true
2.パラメータとしてのラムダ式
Any :ラムダ式の条件を満たす要素がコレクションに1つ以上true
場合はtrue
返します。
var arrayOfStrings = new string[] { "a", "b", "c" };
arrayOfStrings.Any(item => item == "a"); // true
arrayOfStrings.Any(item => item == "d"); // false
3.空のコレクション
Any :コレクションが空でラムダ式が指定されている場合はfalse
返します。
var numbers = new List<int>();
bool result = numbers.Any(i => i >= 0); // false
注: Any
は、条件に一致する要素を見つけるとすぐにコレクションの反復を停止します。つまり、コレクションが必ずしも完全に列挙されるわけではありません。条件に一致する最初の項目を見つけるために十分に列挙されます。
ToDictionary
ToDictionary()
LINQメソッドは、指定されたIEnumerable<T>
ソースに基づいてDictionary<TKey, TElement>
コレクションを生成するために使用できます。
IEnumerable<User> users = GetUsers();
Dictionary<int, User> usersById = users.ToDictionary(x => x.Id);
この例では、 ToDictionary
渡される単一の引数は、各要素のキーを返すFunc<TSource, TKey>
型です。
これは、以下の操作を実行する簡潔な方法です。
Dictionary<int, User> usersById = new Dictionary<int User>();
foreach (User u in users)
{
usersById.Add(u.Id, u);
}
2番目のパラメータをFunc<TSource, TElement>
型のToDictionary
メソッドに渡して、各エントリに追加するValue
を返すこともできます。
IEnumerable<User> users = GetUsers();
Dictionary<int, string> userNamesById = users.ToDictionary(x => x.Id, x => x.Name);
キー値を比較するために使用されるIComparer
を指定することもできます。これは、キーが文字列で、大文字と小文字を区別しない場合に便利です。
IEnumerable<User> users = GetUsers();
Dictionary<string, User> usersByCaseInsenstiveName = users.ToDictionary(x => x.Name, StringComparer.InvariantCultureIgnoreCase);
var user1 = usersByCaseInsenstiveName["john"];
var user2 = usersByCaseInsenstiveName["JOHN"];
user1 == user2; // Returns true
注: ToDictionary
メソッドでは、すべてのキーが一意である必要があります。重複するキーは存在しません。存在する場合、例外がスローされますArgumentException: An item with the same key has already been added.
同じキーを持つ複数の要素があることがわかっているシナリオがある場合は、代わりにToLookup
を使用する方がよいでしょう。
集計
Aggregate
アキュムレータ関数をシーケンスに適用します。
int[] intList = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int sum = intList.Aggregate((prevSum, current) => prevSum + current);
// sum = 55
- 最初のステップで
prevSum = 1
- 2番目の
prevSum = prevSum(at the first step) + 2
- i番目のステップ
prevSum = prevSum(at the (i-1) step) + i-th element of the array
string[] stringList = { "Hello", "World", "!" };
string joinedString = stringList.Aggregate((prev, current) => prev + " " + current);
// joinedString = "Hello World !"
Aggregate
第2のオーバーロードはまた、初期アキュムレータ値であるseed
パラメータを受け取る。これは、コレクションを複数回反復することなく、コレクションの複数の条件を計算するために使用できます。
List<int> items = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };
計算したいitems
のコレクションについて
- 合計
.Count
- 偶数の数
- 各項目を収集する
Aggregate
を使うと、次のようにすることができます:
var result = items.Aggregate(new { Total = 0, Even = 0, FourthItems = new List<int>() },
(accumelative,item) =>
new {
Total = accumelative.Total + 1,
Even = accumelative.Even + (item % 2 == 0 ? 1 : 0),
FourthItems = (accumelative.Total + 1)%4 == 0 ?
new List<int>(accumelative.FourthItems) { item } :
accumelative.FourthItems
});
// Result:
// Total = 12
// Even = 6
// FourthItems = [4, 8, 12]
シードとして匿名型を使用すると、プロパティが読み取り専用であるため、各オブジェクトを新しいオブジェクトでインスタンス化する必要があることに注意してください。カスタムクラスを使用すると、単純に情報を割り当てることができ、 new
は必要ありません(最初のseed
パラメータ
Linqクエリ内で変数を定義する(キーワードを指定する)
linq式の中で変数を定義するには、 letキーワードを使用します。これは、通常、中間サブクエリの結果を格納するために実行されます。たとえば、次のようになります。
int[] numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var aboveAverages = from number in numbers
let average = numbers.Average()
let nSquared = Math.Pow(number,2)
where nSquared > average
select number;
Console.WriteLine("The average of the numbers is {0}.", numbers.Average());
foreach (int n in aboveAverages)
{
Console.WriteLine("Query result includes number {0} with square of {1}.", n, Math.Pow(n,2));
}
出力:
数字の平均は4.5です。
クエリ結果には、9の2乗で3が含まれます。
クエリー結果には、4の正方形を含む4が含まれます。
クエリ結果には、5の平方根を含む5が含まれます。
クエリ結果には、6の平方根を含む6が含まれます。
問合せ結果には7の四角形の7が含まれます。
問合せ結果には、8の正方形を含む8が含まれます。
クエリ結果には、9の平方根が含まれます。
SkipWhile
SkipWhile()
は、最初に不一致になるまで要素を除外するために使用されます(これはほとんどの場合直感的です)
int[] list = { 42, 42, 6, 6, 6, 42 };
var result = list.SkipWhile(i => i == 42);
// Result: 6, 6, 6, 42
DefaultIfEmpty
DefaultIfEmptyは、シーケンスに要素が含まれていない場合、デフォルトの要素を返すために使用されます。この要素は、その型の既定値またはその型のユーザー定義インスタンスです。例:
var chars = new List<string>() { "a", "b", "c", "d" };
chars.DefaultIfEmpty("N/A").FirstOrDefault(); // returns "a";
chars.Where(str => str.Length > 1)
.DefaultIfEmpty("N/A").FirstOrDefault(); // return "N/A"
chars.Where(str => str.Length > 1)
.DefaultIfEmpty().First(); // returns null;
左結合の使用法 :
DefaultIfEmpty
すると、従来のLinq Joinは一致が見つからない場合にデフォルトのオブジェクトを返すことができます。したがって、SQLの左結合として動作します。例:
var leftSequence = new List<int>() { 99, 100, 5, 20, 102, 105 };
var rightSequence = new List<char>() { 'a', 'b', 'c', 'i', 'd' };
var numbersAsChars = from l in leftSequence
join r in rightSequence
on l equals (int)r into leftJoin
from result in leftJoin.DefaultIfEmpty('?')
select new
{
Number = l,
Character = result
};
foreach(var item in numbersAsChars)
{
Console.WriteLine("Num = {0} ** Char = {1}", item.Number, item.Character);
}
ouput:
Num = 99 Char = c
Num = 100 Char = d
Num = 5 Char = ?
Num = 20 Char = ?
Num = 102 Char = ?
Num = 105 Char = i
DefaultIfEmpty
が(デフォルト値を指定せずに)使用され、正しいシーケンスに一致する項目がない場合、プロパティにアクセスする前にそのオブジェクトがnull
ないことを確認する必要があります。それ以外の場合は、 NullReferenceException
が発生します。例:
var leftSequence = new List<int> { 1, 2, 5 };
var rightSequence = new List<dynamic>()
{
new { Value = 1 },
new { Value = 2 },
new { Value = 3 },
new { Value = 4 },
};
var numbersAsChars = (from l in leftSequence
join r in rightSequence
on l equals r.Value into leftJoin
from result in leftJoin.DefaultIfEmpty()
select new
{
Left = l,
// 5 will not have a matching object in the right so result
// will be equal to null.
// To avoid an error use:
// - C# 6.0 or above - ?.
// - Under - result == null ? 0 : result.Value
Right = result?.Value
}).ToList();
SequenceEqual
SequenceEqual
は、2つのIEnumerable<T>
シーケンスを互いに比較するために使用されます。
int[] a = new int[] {1, 2, 3};
int[] b = new int[] {1, 2, 3};
int[] c = new int[] {1, 3, 2};
bool returnsTrue = a.SequenceEqual(b);
bool returnsFalse = a.SequenceEqual(c);
カウントとロングカウント
Count
は、 IEnumerable<T>
内の要素の数を返します。 Count
は、カウントする要素をフィルタリングできるオプションの述語パラメータも公開しています。
int[] array = { 1, 2, 3, 4, 2, 5, 3, 1, 2 };
int n = array.Count(); // returns the number of elements in the array
int x = array.Count(i => i > 2); // returns the number of elements in the array greater than 2
LongCount
同じように動作しますCount
が、の戻り値の型があるlong
してカウントするために使用されているIEnumerable<T>
より長いシーケンスint.MaxValue
int[] array = GetLargeArray();
long n = array.LongCount(); // returns the number of elements in the array
long x = array.LongCount(i => i > 100); // returns the number of elements in the array greater than 100
クエリを段階的に構築する
LINQは遅延実行を使用するため、実際には値を含まず、評価されたときに値を返すクエリオブジェクトを持つことができます。したがって、制御フローに基づいてクエリを動的に構築し、終了したら評価することができます。
IEnumerable<VehicleModel> BuildQuery(int vehicleType, SearchModel search, int start = 1, int count = -1) {
IEnumerable<VehicleModel> query = _entities.Vehicles
.Where(x => x.Active && x.Type == vehicleType)
.Select(x => new VehicleModel {
Id = v.Id,
Year = v.Year,
Class = v.Class,
Make = v.Make,
Model = v.Model,
Cylinders = v.Cylinders ?? 0
});
条件付きでフィルタを適用することができます。
if (!search.Years.Contains("all", StringComparer.OrdinalIgnoreCase))
query = query.Where(v => search.Years.Contains(v.Year));
if (!search.Makes.Contains("all", StringComparer.OrdinalIgnoreCase)) {
query = query.Where(v => search.Makes.Contains(v.Make));
}
if (!search.Models.Contains("all", StringComparer.OrdinalIgnoreCase)) {
query = query.Where(v => search.Models.Contains(v.Model));
}
if (!search.Cylinders.Equals("all", StringComparer.OrdinalIgnoreCase)) {
decimal minCylinders = 0;
decimal maxCylinders = 0;
switch (search.Cylinders) {
case "2-4":
maxCylinders = 4;
break;
case "5-6":
minCylinders = 5;
maxCylinders = 6;
break;
case "8":
minCylinders = 8;
maxCylinders = 8;
break;
case "10+":
minCylinders = 10;
break;
}
if (minCylinders > 0) {
query = query.Where(v => v.Cylinders >= minCylinders);
}
if (maxCylinders > 0) {
query = query.Where(v => v.Cylinders <= maxCylinders);
}
}
条件に基づいてクエリにソート順を追加できます。
switch (search.SortingColumn.ToLower()) {
case "make_model":
query = query.OrderBy(v => v.Make).ThenBy(v => v.Model);
break;
case "year":
query = query.OrderBy(v => v.Year);
break;
case "engine_size":
query = query.OrderBy(v => v.EngineSize).ThenBy(v => v.Cylinders);
break;
default:
query = query.OrderBy(v => v.Year); //The default sorting.
}
クエリは、特定のポイントから開始するように定義できます。
query = query.Skip(start - 1);
特定のレコード数を返すように定義されています。
if (count > -1) {
query = query.Take(count);
}
return query;
}
クエリオブジェクトをToList
、 foreach
ループ、またはToList
やToArray
などの一連の値を返すLINQメソッドのいずれかを使用して結果を評価できます。
SearchModel sm;
// populate the search model here
// ...
List<VehicleModel> list = BuildQuery(5, sm).ToList();
ジップ
Zip
拡張メソッドは2つのコレクションに作用します。これは、位置に基づいて2つの系列の各要素を一緒にペアにします。 Func
インスタンスでは、 Zip
を使用して2つのC#コレクションの要素をペアで処理します。シリーズのサイズが異なる場合、大きなシリーズの余分な要素は無視されます。
「C#in a Nutshell」という本を例に取ると、
int[] numbers = { 3, 5, 7 };
string[] words = { "three", "five", "seven", "ignored" };
IEnumerable<string> zip = numbers.Zip(words, (n, w) => n + "=" + w);
出力:
3 = 3
5 = 5
7 = 7
外側範囲変数を持つGroupJoin
Customer[] customers = Customers.ToArray();
Purchase[] purchases = Purchases.ToArray();
var groupJoinQuery =
from c in customers
join p in purchases on c.ID equals p.CustomerID
into custPurchases
select new
{
CustName = c.Name,
custPurchases
};
ElementAtおよびElementAtOrDefault
ElementAt
はインデックスn
の項目を返します。 n
が列挙型の範囲内にない場合は、 ArgumentOutOfRangeException
スローします。
int[] numbers = { 1, 2, 3, 4, 5 };
numbers.ElementAt(2); // 3
numbers.ElementAt(10); // throws ArgumentOutOfRangeException
ElementAtOrDefault
はインデックスn
の項目を返します。 n
が列挙型の範囲内にない場合は、 default(T)
返します。
int[] numbers = { 1, 2, 3, 4, 5 };
numbers.ElementAtOrDefault(2); // 3
numbers.ElementAtOrDefault(10); // 0 = default(int)
ElementAt
とElementAtOrDefault
は、ソースがIList<T>
場合に最適化され、そのような場合には通常のインデックス作成が使用されます。
ElementAt
場合、指定されたインデックスがIList<T>
サイズより大きい場合、リストはArgumentOutOfRangeException
スローする必要があります(ただし、技術的には保証されません)。
Linq数量子
数量化演算子は、シーケンス内の要素の一部またはすべてが条件を満たす場合にブール値を返します。この記事では、これらの演算子を使用できる一般的なLINQ to Objectsシナリオをいくつか見ていきます。 LINQで使用できる3つの数量演算があります。
All
- シーケンス内のすべての要素が条件を満たすかどうかを判断するために使用されます。例えば:
int[] array = { 10, 20, 30 };
// Are all elements >= 10? YES
array.All(element => element >= 10);
// Are all elements >= 20? NO
array.All(element => element >= 20);
// Are all elements < 40? YES
array.All(element => element < 40);
Any
- シーケンス内の要素が条件を満たすかどうかを判断するために使用されます。例えば:
int[] query=new int[] { 2, 3, 4 }
query.Any (n => n == 3);
Contains
- シーケンスに指定された要素が含まれているかどうかを判断するために使用さContains
。例えば:
//for int array
int[] query =new int[] { 1,2,3 };
query.Contains(1);
//for string array
string[] query={"Tom","grey"};
query.Contains("Tom");
//for a string
var stringValue="hello";
stringValue.Contains("h");
複数のシーケンスに結合する
エンティティCustomer
、 Purchase
およびPurchaseItem
を次のように考えます。
public class Customer
{
public string Id { get; set } // A unique Id that identifies customer
public string Name {get; set; }
}
public class Purchase
{
public string Id { get; set }
public string CustomerId {get; set; }
public string Description { get; set; }
}
public class PurchaseItem
{
public string Id { get; set }
public string PurchaseId {get; set; }
public string Detail { get; set; }
}
上記のエンティティのサンプルデータを次のように考えてみましょう。
var customers = new List<Customer>()
{
new Customer() {
Id = Guid.NewGuid().ToString(),
Name = "Customer1"
},
new Customer() {
Id = Guid.NewGuid().ToString(),
Name = "Customer2"
}
};
var purchases = new List<Purchase>()
{
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[0].Id,
Description = "Customer1-Purchase1"
},
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[0].Id,
Description = "Customer1-Purchase2"
},
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[1].Id,
Description = "Customer2-Purchase1"
},
new Purchase() {
Id = Guid.NewGuid().ToString(),
CustomerId = customers[1].Id,
Description = "Customer2-Purchase2"
}
};
var purchaseItems = new List<PurchaseItem>()
{
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[0].Id,
Detail = "Purchase1-PurchaseItem1"
},
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[1].Id,
Detail = "Purchase2-PurchaseItem1"
},
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[1].Id,
Detail = "Purchase2-PurchaseItem2"
},
new PurchaseItem() {
Id = Guid.NewGuid().ToString(),
PurchaseId= purchases[3].Id,
Detail = "Purchase3-PurchaseItem1"
}
};
今、linqクエリの下で検討してください:
var result = from c in customers
join p in purchases on c.Id equals p.CustomerId // first join
join pi in purchaseItems on p.Id equals pi.PurchaseId // second join
select new
{
c.Name, p.Description, pi.Detail
};
上記のクエリの結果を出力するには:
foreach(var resultItem in result)
{
Console.WriteLine($"{resultItem.Name}, {resultItem.Description}, {resultItem.Detail}");
}
クエリの出力は次のようになります。
得意先1、得意先1 - 購買1、購買1 - 購買項目1
得意先1、得意先1 - 購買2、購買2 - 購買品目1
得意先1、得意先1 - 購買2、購買2 - 購買品目2
得意先2、得意先2 - 購買2、購買3 - 購買品目1
複数のキーに参加する
PropertyInfo[] stringProps = typeof (string).GetProperties();//string properties
PropertyInfo[] builderProps = typeof(StringBuilder).GetProperties();//stringbuilder properties
var query =
from s in stringProps
join b in builderProps
on new { s.Name, s.PropertyType } equals new { b.Name, b.PropertyType }
select new
{
s.Name,
s.PropertyType,
StringToken = s.MetadataToken,
StringBuilderToken = b.MetadataToken
};
上記のjoin
匿名型は、すべてのプロパティが等しい場合にのみオブジェクトが等しいとみなされるため、同じプロパティを含む必要があることに注意してください。それ以外の場合、クエリはコンパイルされません。
Funcで選択 selector - 要素のランキングを取得するために使用します。
Select
拡張メソッドのオーバーロードでは、 Select
れているコレクション内の現在のアイテムのindex
も渡されselect
。これらは、そのいくつかの用途です。
アイテムの「行番号」を取得する
var rowNumbers = collection.OrderBy(item => item.Property1)
.ThenBy(item => item.Property2)
.ThenByDescending(item => item.Property3)
.Select((item, index) => new { Item = item, RowNumber = index })
.ToList();
グループ内のアイテムのランクを取得する
var rankInGroup = collection.GroupBy(item => item.Property1)
.OrderBy(group => group.Key)
.SelectMany(group => group.OrderBy(item => item.Property2)
.ThenByDescending(item => item.Property3)
.Select((item, index) => new
{
Item = item,
RankInGroup = index
})).ToList();
グループのランキングを取得する(Oracleでdense_rankとしても知られている)
var rankOfBelongingGroup = collection.GroupBy(item => item.Property1)
.OrderBy(group => group.Key)
.Select((group, index) => new
{
Items = group,
Rank = index
})
.SelectMany(v => v.Items, (s, i) => new
{
Item = i,
DenseRank = s.Rank
}).ToList();
これをテストするには、以下を使用できます:
public class SomeObject
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public int Property3 { get; set; }
public override string ToString()
{
return string.Join(", ", Property1, Property2, Property3);
}
}
そしてデータ:
List<SomeObject> collection = new List<SomeObject>
{
new SomeObject { Property1 = 1, Property2 = 1, Property3 = 1},
new SomeObject { Property1 = 1, Property2 = 2, Property3 = 1},
new SomeObject { Property1 = 1, Property2 = 2, Property3 = 2},
new SomeObject { Property1 = 2, Property2 = 1, Property3 = 1},
new SomeObject { Property1 = 2, Property2 = 2, Property3 = 1},
new SomeObject { Property1 = 2, Property2 = 2, Property3 = 1},
new SomeObject { Property1 = 2, Property2 = 3, Property3 = 1}
};
TakeWhile
TakeWhile
は、条件が真である限り、シーケンスから要素を返します
int[] list = { 1, 10, 40, 50, 44, 70, 4 };
var result = list.TakeWhile(item => item < 50).ToList();
// result = { 1, 10, 40 }
和
Enumerable.Sum
拡張メソッドは、数値の合計を計算します。
コレクションの要素自体が数値の場合、合計を直接計算することができます。
int[] numbers = new int[] { 1, 4, 6 };
Console.WriteLine( numbers.Sum() ); //outputs 11
要素の型が複雑な型の場合は、ラムダ式を使用して計算する必要がある値を指定できます。
var totalMonthlySalary = employees.Sum( employee => employee.MonthlySalary );
Sum拡張メソッドは、次のタイプで計算できます。
- Int32
- Int64
- シングル
- ダブル
- 小数
コレクションにnull型が含まれている場合は、null-coalescing演算子を使用して、null要素のデフォルト値を設定できます。
int?[] numbers = new int?[] { 1, null, 6 };
Console.WriteLine( numbers.Sum( number => number ?? 0 ) ); //outputs 7
見上げる
ToLookupは、インデックス作成を可能にするデータ構造体を返します。これは拡張メソッドです。これは、foreachループを使用して索引付けまたは列挙できるILookupインスタンスを生成します。エントリは、各キーのグループにまとめられます。 - dotnetperls
string[] array = { "one", "two", "three" };
//create lookup using string length as key
var lookup = array.ToLookup(item => item.Length);
//join the values whose lengths are 3
Console.WriteLine(string.Join(",",lookup[3]));
//output: one,two
もう一つの例:
int[] array = { 1,2,3,4,5,6,7,8 };
//generate lookup for odd even numbers (keys will be 0 and 1)
var lookup = array.ToLookup(item => item % 2);
//print even numbers after joining
Console.WriteLine(string.Join(",",lookup[0]));
//output: 2,4,6,8
//print odd numbers after joining
Console.WriteLine(string.Join(",",lookup[1]));
//output: 1,3,5,7
IEnumerable用の独自のLinq演算子を構築する
Linqの大きな点の1つは、それがとても簡単に拡張できることです。引数がIEnumerable<T>
である拡張メソッドを作成するだけです。
public namespace MyNamespace
{
public static class LinqExtensions
{
public static IEnumerable<List<T>> Batch<T>(this IEnumerable<T> source, int batchSize)
{
var batch = new List<T>();
foreach (T item in source)
{
batch.Add(item);
if (batch.Count == batchSize)
{
yield return batch;
batch = new List<T>();
}
}
if (batch.Count > 0)
yield return batch;
}
}
}
この例では、 IEnumerable<T>
内の項目を固定サイズのリストに分割します。最後のリストにはアイテムの残りの部分が含まれています。拡張メソッドが適用されるオブジェクトが、 this
キーワードを使用して最初の引数として(引数のsource
)どのように渡されるかに注目してください。 yield
キーワードは、出力IEnumerable<T>
の次の項目を出力する前に実行されます( yieldキーワード参照)。
この例は、あなたのコードで次のように使用されます:
//using MyNamespace;
var items = new List<int> { 2, 3, 4, 5, 6 };
foreach (List<int> sublist in items.Batch(3))
{
// do something
}
最初のループでは、サブリストは{2, 3, 4}
、2番目の{5, 6}
ます。
カスタムLinQメソッドは、標準のLinQメソッドと組み合わせることもできます。例えば:
//using MyNamespace;
var result = Enumerable.Range(0, 13) // generate a list
.Where(x => x%2 == 0) // filter the list or do something other
.Batch(3) // call our extension method
.ToList() // call other standard methods
このクエリは、サイズが{0, 2, 4}, {6, 8, 10}, {12}
バッチでグループ化された偶数を返します{0, 2, 4}, {6, 8, 10}, {12}
using MyNamespace;
する必要があることusing MyNamespace;
拡張メソッドにアクセスできるようにします。
ネストされたループの代わりにSelectManyを使用する
2つのリスト
var list1 = new List<string> { "a", "b", "c" };
var list2 = new List<string> { "1", "2", "3", "4" };
すべての順列を出力したい場合は、次のようなネストされたループを使用できます。
var result = new List<string>();
foreach (var s1 in list1)
foreach (var s2 in list2)
result.Add($"{s1}{s2}");
SelectManyを使用すると、
var result = list1.SelectMany(x => list2.Select(y => $"{x}{y}", x, y)).ToList();
Any and First(OrDefault) - ベストプラクティス
私はAny
とFirstOrDefault
が何をしているのかについては説明しません。詳細については、 AnyおよびFirst、FirstOrDefault、Last、LastOrDefault、SingleおよびSingleOrDefaultを参照してください。
コードでよく見られるパターンは、避けるべきです。
if (myEnumerable.Any(t=>t.Foo == "Bob"))
{
var myFoo = myEnumerable.First(t=>t.Foo == "Bob");
//Do stuff
}
このように効率的に書くことができます
var myFoo = myEnumerable.FirstOrDefault(t=>t.Foo == "Bob");
if (myFoo != null)
{
//Do stuff
}
2番目の例を使用すると、コレクションは1回だけ検索され、最初のコレクションと同じ結果が得られます。同じ考え方をSingle
も適用できます。
GroupBy合計とカウント
サンプルクラスを取ってみましょう:
public class Transaction
{
public string Category { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
}
さて、トランザクションのリストを考えてみましょう:
var transactions = new List<Transaction>
{
new Transaction { Category = "Saving Account", Amount = 56, Date = DateTime.Today.AddDays(1) },
new Transaction { Category = "Saving Account", Amount = 10, Date = DateTime.Today.AddDays(-10) },
new Transaction { Category = "Credit Card", Amount = 15, Date = DateTime.Today.AddDays(1) },
new Transaction { Category = "Credit Card", Amount = 56, Date = DateTime.Today },
new Transaction { Category = "Current Account", Amount = 100, Date = DateTime.Today.AddDays(5) },
};
金額とカウントのカテゴリ別合計を計算する場合は、GroupByを次のように使用できます。
var summaryApproach1 = transactions.GroupBy(t => t.Category)
.Select(t => new
{
Category = t.Key,
Count = t.Count(),
Amount = t.Sum(ta => ta.Amount),
}).ToList();
Console.WriteLine("-- Summary: Approach 1 --");
summaryApproach1.ForEach(
row => Console.WriteLine($"Category: {row.Category}, Amount: {row.Amount}, Count: {row.Count}"));
あるいは、これを1ステップで実行することもできます。
var summaryApproach2 = transactions.GroupBy(t => t.Category, (key, t) =>
{
var transactionArray = t as Transaction[] ?? t.ToArray();
return new
{
Category = key,
Count = transactionArray.Length,
Amount = transactionArray.Sum(ta => ta.Amount),
};
}).ToList();
Console.WriteLine("-- Summary: Approach 2 --");
summaryApproach2.ForEach(
row => Console.WriteLine($"Category: {row.Category}, Amount: {row.Amount}, Count: {row.Count}"));
両方の上記のクエリの出力は同じになります:
カテゴリ:アカウントを貯める、金額:66、数:2
カテゴリ:クレジットカード、金額:71、カウント:2
カテゴリ:当座勘定、金額:100、数:1
逆
- シーケンス内の要素の順序を反転します。
- 項目がない場合、
ArgumentNullException: source is null.
スローされますArgumentNullException: source is null.
例:
// Create an array.
int[] array = { 1, 2, 3, 4 }; //Output:
// Call reverse extension method on the array. //4
var reverse = array.Reverse(); //3
// Write contents of array to screen. //2
foreach (int value in reverse) //1
Console.WriteLine(value);
Remeberは、LINQ文のチェーン順に応じてReverse()
が異なることがあります。
//Create List of chars
List<int> integerlist = new List<int>() { 1, 2, 3, 4, 5, 6 };
//Reversing the list then taking the two first elements
IEnumerable<int> reverseFirst = integerlist.Reverse<int>().Take(2);
//Taking 2 elements and then reversing only thos two
IEnumerable<int> reverseLast = integerlist.Take(2).Reverse();
//reverseFirst output: 6, 5
//reverseLast output: 2, 1
Reverse()は、すべてをバッファリングして後方に移動しますが、効率的ではありませんが、どちらもOrderByではありません。
LINQ-to-Objectsには、バッファリング操作(Reverse、OrderBy、GroupByなど)と非バッファリング操作(Where、Take、Skipなど)があります。
例:バッファリングしない逆方向拡張
public static IEnumerable<T> Reverse<T>(this IList<T> list) {
for (int i = list.Count - 1; i >= 0; i--)
yield return list[i];
}
このメソッドは、反復処理中にリストを変更すると問題が発生する可能性があります。
Enumerableの列挙
IEnumerable <T>インターフェイスは、すべての汎用列挙子の基本インターフェイスであり、LINQを理解する典型的な部分です。その中心に、それはシーケンスを表します。
この基本的なインターフェイスは、 Collection <T> 、 Array 、 List <T> 、 Dictionary <TKey、TValue>クラス 、およびHashSet <T>など、すべての汎用コレクションに継承されます。
シーケンスを表すことに加えて、IEnumerable <T>から継承するクラスはIEnumerator <T>を提供する必要があります。列挙子は、列挙型のイテレータを公開し、これらの2つの相互接続されたインタフェースとアイデアは、「列挙可能な列挙」のソースです。
"列挙可能列挙"は重要なフレーズです。列挙型は単純に反復するための構造であり、マテリアライズされたオブジェクトを保持しません。たとえば、ソートするとき、列挙型はソートするフィールドの基準を保持することができますが、 .OrderBy()
を単独で使用するとソート方法のみを知るIEnumerable <T>が返されます。オブジェクトを実体化する呼び出しを使用すると、集合を反復するときのように、列挙型として知られています(たとえば.ToList()
)。列挙プロセスは、シリーズを移動して関連オブジェクト(順序、フィルタ、投影など)を返すために、 どのように列挙可能な定義を使用します。
列挙型が一度列挙されると、オブジェクトの実体化が行われます。これは、 時間の複雑さ (シリーズのサイズに関係する時間 )や空間の複雑さ(シリーズのサイズに関連してどれくらいのスペースを使用する必要があるか)測定される。
IEnumerable <T>から継承する独自のクラスを作成するには、列挙可能な基になる系列に応じて少し複雑にすることができます。一般に、既存のジェネリックコレクションの1つを使用することが最善です。つまり、基本配列として定義された配列を持たずにIEnumerable <T>インターフェイスを継承することも可能です。
たとえば、フィボナッチ系列を基になるシーケンスとして使用します。 Where
の呼び出しは単にIEnumerable
作成し、値のいずれかがマテリアライズされるように列挙できることを列挙するまではありません。
void Main()
{
Fibonacci Fibo = new Fibonacci();
IEnumerable<long> quadrillionplus = Fibo.Where(i => i > 1000000000000);
Console.WriteLine("Enumerable built");
Console.WriteLine(quadrillionplus.Take(2).Sum());
Console.WriteLine(quadrillionplus.Skip(2).First());
IEnumerable<long> fibMod612 = Fibo.OrderBy(i => i % 612);
Console.WriteLine("Enumerable built");
Console.WriteLine(fibMod612.First());//smallest divisible by 612
}
public class Fibonacci : IEnumerable<long>
{
private int max = 90;
//Enumerator called typically from foreach
public IEnumerator GetEnumerator() {
long n0 = 1;
long n1 = 1;
Console.WriteLine("Enumerating the Enumerable");
for(int i = 0; i < max; i++){
yield return n0+n1;
n1 += n0;
n0 = n1-n0;
}
}
//Enumerable called typically from linq
IEnumerator<long> IEnumerable<long>.GetEnumerator() {
long n0 = 1;
long n1 = 1;
Console.WriteLine("Enumerating the Enumerable");
for(int i = 0; i < max; i++){
yield return n0+n1;
n1 += n0;
n0 = n1-n0;
}
}
}
出力
Enumerable built
Enumerating the Enumerable
4052739537881
Enumerating the Enumerable
4052739537881
Enumerable built
Enumerating the Enumerable
14930352
2番目のフィッティング(fibMod612)の強さは、フィボナッチ数の集合全体を注文する呼び出しを行ったにもかかわらず、 .First()
を使って1つの値しか取られなかったため、時間の複雑さはO(n)順序付けアルゴリズムの実行中に比較される必要があった。これは、われわれの列挙子が1つの値しか求めていないため、列挙体全体を実現する必要がないからです。使用しなければならなかった.First()
.Take(5)
代わりに.Take(5)
を使用すると、列挙子は5つの値を要求し、最大5つの値を.First()
する必要があります。全体のセットを注文してから最初の5つの値を取ることが必要と比較すると、の原則は、実行時間と多くのスペースを節約できます。
OrderBy
指定された値でコレクションをオーダーします。
値が整数 、 倍精度または浮動小数点の場合は、 最小値で始まります 。つまり、最初に負の値が得られます。ゼロ以降は正の値よりも大きくなります(例1を参照)。
charで注文すると、このメソッドはcharのascii値を比較してコレクションをソートします(例2を参照)。
文字列を並べ替えると、OrderByメソッドはCultureInfoを調べることによってそれらを比較しますが、アルファベットの最初の文字 (a、b、c ...)から始まっています。
このような順序は昇順と呼ばれ、逆の場合は降順にする必要があります(OrderByDescendingを参照)。
例1:
int[] numbers = {2, 1, 0, -1, -2};
IEnumerable<int> ascending = numbers.OrderBy(x => x);
// returns {-2, -1, 0, 1, 2}
例2:
char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z', 'Z'};
IEnumerable<char> ascending = letters.OrderBy(x => x);
// returns { ' ', '!', '+', '1', '9', '?', 'A', 'B', 'Y', 'Z', '[', 'a', 'b', 'y', 'z', '{' }
例:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var people = new[]
{
new Person {Name = "Alice", Age = 25},
new Person {Name = "Bob", Age = 21},
new Person {Name = "Carol", Age = 43}
};
var youngestPerson = people.OrderBy(x => x.Age).First();
var name = youngestPerson.Name; // Bob
OrderByDescending
指定された値でコレクションをオーダーします。
値が整数 、 倍精度または浮動小数点の場合は、 最大値から開始します 。つまり、ゼロとそれ以降の値よりも正の値が最初に得られます(例1を参照)。
charで注文すると、このメソッドはcharのascii値を比較してコレクションをソートします(例2を参照)。
文字列を並べ替えると、OrderByメソッドはCultureInfoを調べることによってそれらを比較しますが、アルファベット(z、y、x、...)の最後の文字から始まっています。
このような順序は降順と呼ばれ、逆の場合は昇順にする必要があります(OrderBy参照)。
例1:
int[] numbers = {-2, -1, 0, 1, 2};
IEnumerable<int> descending = numbers.OrderByDescending(x => x);
// returns {2, 1, 0, -1, -2}
例2:
char[] letters = {' ', '!', '?', '[', '{', '+', '1', '9', 'a', 'A', 'b', 'B', 'y', 'Y', 'z', 'Z'};
IEnumerable<char> descending = letters.OrderByDescending(x => x);
// returns { '{', 'z', 'y', 'b', 'a', '[', 'Z', 'Y', 'B', 'A', '?', '9', '1', '+', '!', ' ' }
例3:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
var people = new[]
{
new Person {Name = "Alice", Age = 25},
new Person {Name = "Bob", Age = 21},
new Person {Name = "Carol", Age = 43}
};
var oldestPerson = people.OrderByDescending(x => x.Age).First();
var name = oldestPerson.Name; // Carol
連合
2つのコレクションをマージします(重複を削除しません)。
List<int> foo = new List<int> { 1, 2, 3 };
List<int> bar = new List<int> { 3, 4, 5 };
// Through Enumerable static class
var result = Enumerable.Concat(foo, bar).ToList(); // 1,2,3,3,4,5
// Through extension method
var result = foo.Concat(bar).ToList(); // 1,2,3,3,4,5
含有
MSDN:
指定された
IEqualityComparer<T>
を使用してシーケンスに指定された要素が含まれるかどうかを判定します。
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var result1 = numbers.Contains(4); // true
var result2 = numbers.Contains(8); // false
List<int> secondNumberCollection = new List<int> { 4, 5, 6, 7 };
// Note that can use the Intersect method in this case
var result3 = secondNumberCollection.Where(item => numbers.Contains(item)); // will be true only for 4,5
ユーザー定義オブジェクトの使用:
public class Person
{
public string Name { get; set; }
}
List<Person> objects = new List<Person>
{
new Person { Name = "Nikki"},
new Person { Name = "Gilad"},
new Person { Name = "Phil"},
new Person { Name = "John"}
};
//Using the Person's Equals method - override Equals() and GetHashCode() - otherwise it
//will compare by reference and result will be false
var result4 = objects.Contains(new Person { Name = "Phil" }); // true
Enumerable.Contains(value, comparer)
オーバーロードの使用:
public class Compare : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
return x.Name == y.Name;
}
public int GetHashCode(Person codeh)
{
return codeh.Name.GetHashCode();
}
}
var result5 = objects.Contains(new Person { Name = "Phil" }, new Compare()); // true
Contains
スマートな使用法は、複数のif
節をContains
呼び出しに置き換えることです。
だからこれをする代わりに:
if(status == 1 || status == 3 || status == 4)
{
//Do some business operation
}
else
{
//Do something else
}
これを行う:
if(new int[] {1, 3, 4 }.Contains(status)
{
//Do some business operaion
}
else
{
//Do something else
}