サーチ…


前書き

LINQはtegrated Q ueryIN 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

.NET Fiddleのライブデモ

LINQクエリ構文の使用

initials = from tree in trees
           select tree.Substring(0, 1);

メソッドの連鎖

多くのLINQ関数IEnumerable<TSource>動作し、 IEnumerable<TResult>も返します。型パラメータTSourceTResultは、問題のメソッドとそれに渡された関数に応じて、同じ型を参照する場合と参照しない場合があります。

これのいくつかの例があります

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つのステートメントで多くのシーケンスベースの操作を実行するために使用できます。

たとえば、 SelectWhere 、および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

.NET Fiddleのライブデモ

一般的なIEnumerable<T>型を拡張して返す関数はすべて、単一のステートメントで連鎖句として使用できます。この流暢なプログラミングスタイルは強力で、独自の拡張メソッドを作成するときには考慮する必要があります。

範囲と繰り返し

EnumerableRangeRepeat静的メソッドは、単純なシーケンスを生成するために使用できEnumerable

範囲

Enumerable.Range()は、開始値とカウントが与えられた整数のシーケンスを生成します。

// Generate a collection containing the numbers 1-100 ([1, 2, 3, ..., 98, 99, 100])
var range = Enumerable.Range(1,100);

.NET Fiddleのライブデモ

繰り返す

Enumerable.Repeat()は、要素と必要な繰り返し回数を指定して繰り返し要素のシーケンスを生成しEnumerable.Repeat()

// Generate a collection containing "a", three times (["a","a","a"])
var repeatedValues = Enumerable.Repeat("a", 3);

.NET Fiddleのライブデモ

スキップ&テイク

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

.NET Fiddleのライブデモ

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();

.NET Fiddleのライブデモ

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();

.NET Fiddleのライブデモ

最終()

  • シーケンスの最後の要素、または指定された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();

推奨事項

  • FirstOrDefaultLastOrDefaultまたは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

.NET Fiddleのライブデモ

この場合.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

.NET Fiddleのライブデモ

この場合、要素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));
    }
}

出力:

ハヌカ

.NET Fiddleのライブデモ

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);
}

出力:

ボブ
ジャック
ジム
ジョン

.NET Fiddleのライブデモ

すべて

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

.NET Fiddleのライブデモ

ジョイン

結合は、共通のキーを介してデータを保持する異なるリストまたはテーブルを結合するために使用されます。

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つ以上の異なるテーブルを結合します(この例では、 firstsecondは共通キー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型のオブジェクトを作成します。

.NETのバイブルでのライブデモ

独特な

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は、コレクションの要素が条件に一致するかどうをチェックするために使用されます。
.AllAny、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は、条件に一致する要素を見つけるとすぐにコレクションの反復を停止します。つまり、コレクションが必ずしも完全に列挙されるわけではありません。条件に一致する最初の項目を見つけるために十分に列挙されます。

.NET Fiddleのライブデモ

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のコレクションについて

  1. 合計.Count
  2. 偶数の数
  3. 各項目を収集する

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;
}

クエリオブジェクトをToListforeachループ、またはToListToArrayなどの一連の値を返す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)

ElementAtElementAtOrDefaultは、ソースが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");

複数のシーケンスに結合する

エンティティCustomerPurchaseおよび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

.NET Fiddleのライブデモ

複数のキーに参加する

  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) - ベストプラクティス

私はAnyFirstOrDefaultが何をしているのかについては説明しません。詳細については、 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

.NET Fiddleのライブデモ

  • シーケンス内の要素の順序を反転します。
  • 項目がない場合、 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>ArrayList <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番目のフィッティング(fi​​bMod612)の強さは、フィボナッチ数の集合全体を注文する呼び出しを行ったにもかかわらず、 .First()を使って1つの値しか取られなかったため、時間の複雑さはO(n)順序付けアルゴリズムの実行中に比較される必要があった。これは、われわれの列挙子が1つの値しか求めていないため、列挙体全体を実現する必要がないからです。使用しなければならなかった.First() .Take(5)代わりに.Take(5)を使用すると、列挙子は5つの値を要求し、最大5つの値を.First()する必要があります。全体のセットを注文してから最初の5つの値を取ることが必要と比較すると、の原則は、実行時間と多くのスペースを節約できます。

OrderBy

指定された値でコレクションをオーダーします。

値が整数倍精度または浮動小数点の場合は、 最小値で始まります 。つまり、最初に負の値が得られます。ゼロ以降は正の値よりも大きくなります(例1を参照)。

charで注文すると、このメソッドはcharascii値を比較してコレクションをソートします(例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で注文すると、このメソッドはcharascii値を比較してコレクションをソートします(例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
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow