2015-12-03 5 views
5

Ich habe eine Liste von Objekten, die ich auf nur diejenigen reduzieren möchte, die Eigenschaften in einer separaten Liste enthalten.Enthält auf Liste ist zu langsam, wie zu verbessern?

List1 ist eine Liste einfacher Strings.

List2 ist eine Liste von Objekten mit zwei String-Eigenschaften. A und B.

Alle Elemente, bei denen A und B in Liste1 nicht vorhanden sind, sollten entfernt werden.

Dieser Prozess ist sehr zeitabhängig und muss so schnell wie möglich durchgeführt werden. Derzeit habe ich die folgende Implementierung;

var List1 = new List<String>() {"Around", "9000", "strings"}; //List of about 9000 strings 
var List2 = databaseList.ToList(); //Around 2.5 million objects 

var reducedList = new HashSet<Object>();    
foreach (var item in List2) 
{ 
    if(List1.Contains(item.A) && List1.Contains(item.B)) 
    { 
     reducedList.Add(item); 
    } 
} 

Dieser Vorgang dauert etwa 7 Sekunden, was für meine aktuellen Anforderungen zu langsam ist.

Ich habe versucht, dies mit LINQ ausführen, gibt aber das gleiche Ergebnis, etwa 7 Sekunden.

var reducedList = List2.Where(r => List1.Contains(r.A)).Where(r => List1.Contains(r.B)).ToList(); 

Irgendwelche Vorschläge, was ich tun kann, um dies zu verbessern?

EDIT: Ich kann keine dieser auf der SQL-Seite der Dinge tun, da die 9000 Zeichenfolgen, die ich gegen vergleichen müssen nicht „übersetzt“ werden kann in und SQL-Abfrage, aber über dem erlaubten 2100 gehen Eingabeparameter, die in unserem SQL Server Setup erlaubt sind.

+7

[HashSet] (https://www.google.com/search?q=hashset&ie=utf-8&oe=utf-8). –

+0

Wie lange dauert es, ** nur ** eine "foreach" über alle Elemente in der Datenbank zu machen? Takten Sie auch die 'foreach'-Schleife oder die beiden Initialisierungsanweisungen? –

+3

Die foreach over databaseList, die über 2,5 Millionen Objekte enthält, stört mich; Geben Sie auch den Namen (databaseList) an Sind Sie sicher, dass Sie keine Abfrage auf db-Ebene durchführen können? –

Antwort

0

Wie @Ondrej Švejdar hingewiesen, wenn databaseList von EntityFramework kommt, Sie dann sollten Sie nicht ToList() nennen, da es eine DB-Abfrage macht, die 2,5 Millionen Datensätze

var reducedList = databaseList 
       .Where(r => List1.Contains(r.A) && List1.Contains(r.B)) 
       .ToList(); 

auch zurück, wenn List1 herkommt Datenbank (ich hoffe, dass 9000 ist eine große Anzahl manuell zu erstellen), dann erwägen, join Operator zu verwenden.

+1

Wenn "List1" eine speicherinterne Liste ist, dann würden die 9000 Elemente in SQL-Parameter übersetzt werden, die wahrscheinlich nicht kompilieren würden (nicht in SQL Server sowieso). – Maarten

2

Zuerst werfen wir die erste Liste schneller machen Nachschlag auf:

var sought = new HashSet<String>() {"Around", "9000", "strings"}; 

Auch Warum sich plagen ziehen eine Liste im Speicher, wenn Sie gerade durchläuft es zu durchlaufen. Es sei denn, Sie wollen List2 für einen anderen Zweck verwenden, es tut nichts.

foreach (var item in databaseList) 
{ 
    if(sought.Contains(item.A) && sought.Contains(item.B)) 
    { 
    reducedList.Add(item); 
    } 
} 

Auch Ihre reducedList hashlist entsprechend als new HashList<TheActualTypeOfTheItemsHere> eingeben.

Wenn dieser Typ IEquatable<T> nicht implementiert, fügen Sie diese Implementierung hinzu. Wenn das unmöglich ist, dann erstellen Sie eine entsprechende IEqualityComparer<T> und verwenden Sie das in reducedList 's Konstruktor.

+0

Die Liste mit 9000 Strings würde in 9000 Parameter übersetzt werden, und die SQL etwas wie 'WHERE item.A = value1 ODER item.A = value2 OR ...'. Auch SQL Server unterstützt nicht so viele Parameter. – Maarten

+0

@Maarten heh. Ich habe mir nicht einmal die eigentlichen Saiten angeschaut und dachte mir "naja, wenn es nur ein paar Saiten in der ersten Liste geben wird ..."! –

+0

@Maarten ein bisschen besser jetzt für diesen Zweck. –

3

Ich habe es nicht versucht, aber wahrscheinlich würde es die Leistung erhöhen.

var List1 = new List<String>() {"Around", "9000", "strings"}; 
var List2 = databaseList.ToList(); //Around 2.5 million objects 

var reducedList = List2.RemoveAll(i => !List1.Contains(i.A) && !List1.Contains(i.B)).ToList(); 
+0

'Liste .RemoveAll (Prädikat )' gibt ein int zurück, keine Liste, also kompiliert es nicht. Auch die '.Contains (...)' werden immer noch ausgeführt, also warum sollte das besser sein? – Maarten

0

Die Version der Datenbank könnte ein Problem sein: Referenz: Slower sqlite Da ich weiß nicht, was der König von DB Sie verwenden, könnte dies „nutzlos“ sein.Aber schau, ob deine DB die neueste Version hat und auch wie schnell es sein kann. Testen Sie Ihr Programm auf einem anderen PC/Browser/Telefon und sehen Sie, ob Sie die gleichen Ergebnisse erhalten.

Jetzt sollten Sie finden, was genau dauert eine lange Zeit. Versuchen Sie, Ihre if-Anweisung zu entfernen und sehen Sie, ob sich die Geschwindigkeit verbessert. Wenn es nicht verbessert wird, ist die Abfrage der Geschwindigkeit ein Problem. Wenn dies der Fall ist, versuchen Sie, Ihre Datenbank auf eine Weise abzufragen, die Sie nicht benötigen, wenn.

0

könnten Sie versuchen IEquatable auf Ihrem Objekt Implementierung, da es die Methode, die Contains nennen, um zu sehen, ob das Objekt in der Liste ist

diesen post Informationen für mehr sehen.

0

Wie groß ist List1 normalerweise? Wenn es eine kleine Liste wie in Ihrer Probe ist, dann wäre es in Ordnung, mit einer Liste zu bleiben. Wenn das nicht der Fall ist, können Sie stattdessen bessere Ergebnisse mit einem HashSet erzielen.

Die eigentlichen Spiel-Wechsler, glaube ich, vermeiden die List2 mit den 2,5 Millionen Objekten laden, nur später, sie zu filtern. Wenn Datenbankliste irgendeine Art von IEnumerable zu einem DbSet ist, können Sie bessere Ergebnisse mit so etwas wie erhalten:

var List1 = new List<String>() {"Around", "9000", "strings"}; 
var reducedList = (from item in databaseList 
        where List1.Contains(item.A) && List1.Contains(item.B) 
        select item).ToList(); 

eine HashSet für Ihre reduzierte Liste Mit nur Einfügungen verlangsamen. Wenn Sie es verwenden, um Duplikate zu vermeiden oder die Suche später zu beschleunigen, sollten Sie es behalten. Sonst wird eine Liste besser sein.

Verwandte Themen