LINQ to Objects und verbesserte Perf mit einem Index?

8

Ich verwende LINQ to Objects und frage mich, ob es möglich ist, die Leistung meiner Abfragen zu verbessern, indem ich einen Index nutze, den ich habe. Dies wird am besten mit einem Beispiel erklärt. Stellen Sie sich einen einfachen Typ vor ...

%Vor%

Und eine einfache Abfrage würde ich dagegen machen ...

%Vor%

Wenn ich LINQ to Objects richtig verstehe, wird die Implementierung der Where-Erweiterungsmethode alle 50.000 Instanzen in der people-Auflistung auflisten, um die 100 zu finden, die tatsächlich übereinstimmen. Wie es passiert, habe ich bereits einen Index der People-Sammlung, der nach Alter sortiert ist. So ...

%Vor%

Offensichtlich würde es Sinn machen, wenn ich das Wo die SortedList verwenden könnte, so dass es nicht mehr alle 50.000 Instanzen aufzählen muss, stattdessen den Bereich von 100 übereinstimmenden Einträgen finden und so Zeit sparen.

Ist es möglich, LINQ auf Objekte zu erweitern, um meine Situation zu aktivieren? Ist es schon möglich, aber mir fehlt die Technik?

    
Phil Wright 03.10.2011, 21:49
quelle

4 Antworten

5

Es gibt bereits ein Projekt, von dem ich glaube, dass es genau das tut - i4o . Ich kann nicht sagen, dass ich es selbst benutzt habe, aber es klingt wie die Art von Dingen, die du willst ... du musst deinen vorhandenen Code vielleicht ein wenig jonglieren, aber es lohnt sich, es anzuschauen.

Wenn das nicht hilft, könnten Sie zumindest Ihre eigenen Erweiterungsmethoden für SortedList<TKey, TValue> schreiben. Sie könnten Ihre <%> co <%> -Klausel wahrscheinlich nicht einfach verwenden, aber Sie könnten Ihre eigenen Methoden verwenden, die einen minimalen und einen maximalen Wert annehmen. Sie könnten auch möchten, dass sie auf where angewendet werden, wo Sie bestätigen , dass Sie die Werte bereits entsprechend sortiert haben (gemäß einem Vergleich).

Zum Beispiel (vollständig ungetestet):

%Vor%

(Wenn Sie nur IList<T> anstelle von List<T> haben, können Sie IList<T> , obwohl Sie eine benutzerdefinierte List<T>.BinarySearch erstellen müssten.)

Sehen Sie sich auch IComparer<T> in .NET 4 an.

>     
Jon Skeet 03.10.2011, 21:53
quelle
5

Sie haben Recht, dass die von Ihnen geschriebene Abfrage die gesamte Liste aufzählt, da LINQ natürlich nichts von Ihren Daten annehmen kann.

Wenn Sie eine SortedList haben, können Sie das mit den SkipWhile / TakeWhile linq Methoden ausnutzen:

%Vor%

BEARBEITEN

@ Davy8 hat natürlich Recht, dass dieser im schlimmsten Fall immer noch die gleiche Leistung hat. Sehen Sie sich die anderen Antworten an, um den ersten Wert schneller zu finden.

Wenn Sie diese Operation mehrmals für verschiedene Altersbereiche durchführen müssen, können Sie sie wahrscheinlich auch beschleunigen, indem Sie das Alter gruppieren:

%Vor%     
jeroenh 03.10.2011 22:03
quelle
2

Die LINQ-Abfragesyntax verwendet tatsächlich jede Erweiterungsmethode mit dem Namen Where , die mit der Signatur übereinstimmt, sodass Sie immer eine eigene schreiben können, die Ihren spezifischen Typ so behandelt, wie Sie möchten.

%Vor%

...

%Vor%

Dann können Sie jede gewünschte Logik anwenden. Ich glaube, dass die normalen Überladungsregeln für Methoden gelten, um zu bestimmen, welche Where -Dehnungsmethode aufgerufen werden würde.

    
Davy8 03.10.2011 22:02
quelle
0

In einem vorsortierten Container wird die Effizienz erreicht, indem das erste Element schnell gefunden wird. Sobald Sie das erste Element gefunden haben, rufen Sie einfach die folgenden Elemente linear ab, bis Sie das Ende Ihres Bereichs gefunden haben.

Angenommen, Ihr SortedList ist nach Person.Age sortiert, können Sie das erste Element des Bereichs mit SortedList.IndexOfKey finden, was eine binäre Suche Algorithmus; Daher ist diese Methode eine O (log n) -Operation.

( Ich glaube nicht, dass Sie Ihren Code ändern können, so dass Enumerable.Where plötzlich intelligenter wird und den Bereich mit der binären Suche beginnt. )

--- BEARBEITEN ---

Was du wirklich brauchst, ist List.BinarySearch oder Array.BinarySearch . Mit SortedList.IndexOfKey können Sie nicht den Index der engsten Übereinstimmung erhalten, falls die exakte Übereinstimmung nicht existiert. Oder Sie können die binäre Suche selbst implementieren.

    
Branko Dimitrijevic 03.10.2011 22:28
quelle

Tags und Links