2

FieldFooを持つクラスがあり、オブジェクトのコレクションをValueで並べ替えたいとします。1 つの方法はのメソッドを実装することですが、このように言語統合クエリ (LINQ) を使用して実行することもできます。Int32BarFooBarIComparableCompareTo()

List<Foo> foos = new List<Foo>();
// assign some values here
var sortedFoos = foos.OrderBy(f => f.Bar);

これsortedFoosで、foosソートされたコレクションができました。ただし、System.Diagnostics.StopWatchオブジェクトを使用してコレクションの並べ替えにかかった時間を測定すると、OrderBy()常に 0 ミリ秒になります。しかし、コレクションを印刷するときはいつでも、sortedFoos明らかにソートされています。そんなことがあるものか。コレクションをソートするのに文学的な時間はかかりませんが、メソッドの実行後にコレクションはソートされますか? 誰かがそれがどのように機能するかを説明できますか? そしてまた一つのこと。コレクションを並べ替えた後、foos別の要素を追加したとします。コレクションを印刷するたびに、追加した要素が最後にあるはずですよね?違う !コレクションは、その要素を追加しても、追加した要素はコレクションfoosの一部だったように並べ替えられますfoosfoos並べ替え後。私はそれがどのように機能するのか理解できません。誰かが私のためにそれを明確にすることができますか?!

4

4 に答える 4

5

ほとんどすべての LINQ メソッドは遅延評価を使用します。それらはすぐには何もしませんが、データを要求したときに正しいことを行うようにクエリを設定します。

OrderByWhereもこのモデルに従いますが、 やのようなメソッドよりも怠惰ではありませんSelect。の結果から最初の結果を要求すると、ソースからすべてOrderByのデータが読み取られ、すべてが並べ替えられてから、最初の要素が返されます。これをたとえば、プロジェクションから最初の要素を要求しても、ソースから最初の要素のみを要求する場合と比較してください。Select

LINQ to Objects が舞台裏でどのように機能するかに興味がある場合は、私のEdulinq ブログ シリーズ(LINQ to Objects の完全な再実装) を読むことをお勧めします。ブログ記事では、各メソッドの動作と実装について説明しています。

(私自身の の実装ではOrderBy、実際には遅延ソートのみを行います。クイック ソートを使用し、次の要素を返すのに「ちょうどよい」ソートを使用します。これにより、次のような処理largeCollection.OrderBy(...).First()が大幅に高速化されます。)

于 2013-06-19T09:03:36.940 に答える
3

LINQ は遅延実行を信じています。これは、反復または結果へのアクセスを開始したときにのみ式が評価されることを意味します。

于 2013-06-19T09:02:49.430 に答える
1

OrderBy拡張機能はIComparer、適切なオーバーロードを介して代替が渡されない限り、作業中の型のデフォルトを使用します。

ソート作業はIOrderedEnumerable<T>、ステートメントによって返された が最初にアクセスされるまで延期されます。最初のアクセスの前後に を配置するStopwatchと、並べ替えにかかる時間がわかります。

ステートメントは s を返す複数の呼び出しから形成される可能性があるため、これは非常に理にかなっていますIOrderedEnumerable。順序付けの呼び出しは連鎖しているため、結果を流暢に拡張し、最終的に返さIOrderedEnumerableれたオブジェクトが可能な限り最も適切な方法で並べ替えを実行できるようにします。これはおそらく、すべての呼び出しを連鎖させてIComparer一度ソートすることで達成されます。貪欲な実装では、無駄に何度もソートする必要があります。

たとえば、

class MadeUp
{
    public int A;
    public DateTime B;
    public string C;
    public Guid D;
}

var verySorted = madeUps.OrderBy(m => m.A)
                    .ThenBy(m => m.B)
                    .ThenByDescending(m => m.C)
                    .ThenBy(m => m.D);

が貪欲に評価された場合verySorted、シーケンス内のすべてのプロパティが評価され、シーケンスは 4 回並べ替えられます。linq の linq 実装は、IOrderedEnumerable並べ替えを列挙まで延期するため、プロセスを最適化できます。

、、およびのIComparers は、この単純化された表現のような複合デリゲートに組み合わせることができます。ABCD

int result
result = comparerA(A, B);
if (result == 0)
{
    result = comparerB(A, B);
    if (result == 0)
    {
        result = comparerC(A, B);
        if (result == 0)
        {
            result = comparerD(A, B);
        }
    }
}

return result;

次に、複合デリゲートを使用して、シーケンスを 1 回並べ替えます。

于 2013-06-19T09:02:47.233 に答える
0

新しいコレクションを取得するには、ToList() を追加する必要があります。そうしないと、sortedFoos の反復処理を開始するときに OrderBy が呼び出されます。

List<Foo> foos = new List<Foo>();
// assign some values here
var sortedFoos = foos.OrderBy(f => f.Bar).ToList();
于 2013-06-19T09:06:54.250 に答える