6

IEnumerable<T>オブジェクト グラフの複数のレベルで結果をフィルター処理しようとしている場合、これを行うために拡張メソッドをチェーンするための推奨される方法はありますか?

私はあらゆる拡張メソッドとラムダの使用にオープンですが、残りのコードベースとの一貫性を保つために LINQ 構文を使用したくないと考えています。

フィルタリングをメソッドのにプッシュするか、別のメソッドをチェーンするだけselectorの方が良いですか? または、より良い解決策はありますか?SelectMany()Where()

最適なオプションを特定するにはどうすればよいですか? このテスト ケースでは、すべてがメモリ内で直接利用可能です。明らかに、以下の両方のサンプルが現在同じ正しい結果を生成しています。どちらか(または別のオプション)が好まれる理由を探しているだけです。

public class Test
{
    // I want the first chapter of a book that's exactly 42 pages, written by
    // an author whose name is Adams, from a library in London.
    public Chapter TestingIEnumerableTExtensionMethods()
    {
        List<Library> libraries = GetLibraries();

        Chapter chapter = libraries
            .Where(lib => lib.City == "London")
            .SelectMany(lib => lib.Books)
            .Where(b => b.Author == "Adams")
            .SelectMany(b => b.Chapters)
            .First(c => c.NumberOfPages == 42);

        Chapter chapter2 = libraries
            .Where(lib => lib.City == "London")
            .SelectMany(lib => lib.Books.Where(b => b.Author == "Adams"))
            .SelectMany(b => b.Chapters.Where(c => c.NumberOfPages == 42))
            .First();
    }

サンプル オブジェクト グラフは次のとおりです。

public class Library
{
    public string Name { get; set; }
    public string City { get; set; }
    public List<Book> Books { get; set; }
}

public class Book
{
    public string Name { get; set; }
    public string Author { get; set; }
    public List<Chapter> Chapters { get; set; }
}

public class Chapter
{
    public string Name { get; set; }
    public int NumberOfPages { get; set; }
}
4

4 に答える 4

3

どちらが最も可能性が高いかは、使用しているLINQの実装によって異なります。LinqToSqlは、メモリ内フィルタリングとは異なる動作をします。単純な実装ではシーケンスの早い段階でより多くのレコードがフィルタリングされるため、句の順序は使用されるデータに応じてパフォーマンスに影響を与えるはずです。つまり、後のメソッドでの作業が少なくなります。

2つの例では、パフォーマンスの違いはごくわずかであり、他の句から独立して各句を簡単に変更できるため、最初の例を優先すると思います。

最良の選択肢を決定することに関しては、それは他のものと同じです:測定。

于 2012-04-09T20:07:50.877 に答える
2

あなたが持っている最初の表現はわずかですが、取るに足らないほど速くなると思います。どちらかが速いかどうかを実際に判断するには、プロファイラーまたはストップウォッチを使用して時間を計る必要があります。

どちらにしても、読みやすさには大きな影響はないようです。ネストのレベルが少ないため、最初のアプローチを好みます。それはすべてあなたの個人的な好みに依存します。

于 2012-04-09T20:06:39.970 に答える
1

これは、基盤となるLINQプロバイダーがどのように機能するかによって異なります。LINQ to Objectsの場合、この場合の両方で、ほぼ同じ量の作業が必要になります。しかし、それは最も単純な(最も単純な)例であるため、それを超えると言うのは難しいです。

于 2012-04-09T20:06:23.357 に答える
0

スタイルの問題ですが、これはあなたに別の角度を与えるかもしれません...
私は時々このようなことをしていることに気づきます...

return libraries.Filter(
        l => l.City == "",
        l => l.Books,
        b => b.Author == "Adams",
        b => b.Chapters,
        c => c.NumberOfPages == 42
        );

...拡張子が何であるかを推測できる場所、次のような...

public static IEnumerable<TC> Filter<TL, TB, TC>(this IEnumerable<TL> list,
    Func<TL, bool> whereLs,
    Func<TL, IEnumerable<TB>> selectBs,
    Func<TB, bool> whereBs,
    Func<TB, IEnumerable<TC>> selectCs,
    Func<TC, bool> whereCs
    )
{
    return list
        .Where(whereLs)
        .SelectMany(selectBs)
        .Where(whereBs)
        .SelectMany(selectCs)
        .Where(whereCs);
}

...また....

...    
{
    return list
        .Where(whereLs)
        .SelectMany(l => selectBs(l).Where(whereBs))
        .SelectMany(b => selectCs(b).Where(whereCs));
}

そして、組み合わせ/オプションは、あなたが持っているもの、「コードを持っているのが好き」(もう少し抽象化するか、「キャプチャ」、「パラメータ化」PerCityAuthorPages(_city, _author, _numPages);など) に応じて多くあります。

...基本的に、私はすべての「場所」、「選択」などを嫌います。「短い形式」を使用すると、どれが、どこで、どれを選択するかが非常に明確であり、非常に「短い形式」であり、文字数がはるかに少なくなります。

また、Where/Select の組み合わせに関する決定を後で延期することもできます (ニーズ、プロバイダーに基づいて、どちらか一方を実行します)。

そして@Telastynは非常に正しいです.LINQプロバイダーは、たとえば、いくつかの実装コードを見ると
、すべての式が削減されているなど
、非常に非決定論的です(つまり、プロバイダーからプロバイダーへ).SQLなどにマッピングされる可能性があります
がこれは、私が思うほとんどの場合と同じようにマップする必要があります。

于 2012-04-09T23:23:28.293 に答える