Ich frage mich, ob das Füllen einer Liste von Objekten in einem Objekt schneller erledigt werden kann als das, was ich sehe, wenn ich es ausführe. Ich fülle die CABCodes- & CABDetails-Listen mit einer einfachen Abfrage mit Dapper mit .ToList ();
So sind beide Listen im Speicher, aber die foreach-Operation dauert etwa 20 Sekunden.
CABCodes: ~ 10.000 Objekte
CABDetails: ~ 60.000 Objekte
List<CABCode> CABCodes = new List<CABCode>();
List<CABDetail> CABDetails = new List<CABDetail>();
public class CABCode {
public int Sequence { get; set; }
public string Code { get; set; }
public int Group { get; set; }
public List<CABDetail> Details { get; set; }
}
public class CABDetail {
public int CABSequence { get; set; }
public int Proptype { get; set; }
public string Propvalue { get; set; }
}
foreach (var c in this.CABCodes) {
c.Details = this.CABDetails.Where(x => x.CABSequence == c.Sequence).ToList();
}
Gibt es eine viel effizientere Methode, dies zu erreichen?
Sie haben O (M * N) algorithmische Zeit. Der folgende Code macht O (M + N), was schnell ist:
var cabDetailsBySequence = CABDetails.ToLookup(d=>d.CABSequence);
foreach (var c in this.CABCodes) {
c.Details = cabDetailsBySequence[c.Sequence].ToList();
}
UPDATE: Ich habe überprüft, dass es unter 110ms funktioniert, mit 100 verschiedenen Sequenzcodes.
Hier ist der Testaufbau:
CABCodes = Enumerable.Range(0, 10000).Select(i=>new CABCode{Sequence = i%100}).ToList();
CABDetails = Enumerable.Range(0, 60000).Select(i=>new CABDetail{CABSequence = i%100}).ToList();
UPDATE 2: Und Sie können es noch schneller machen, (20 mal aprox), wenn es Ihnen nichts ausmacht, auf die gleichen Listen in verschiedenen CABCode-Instanzen zu verweisen, und noch schneller, wenn Sie es parallel tun. So läuft es auf meinem 8-Kern-System unter einer Millisekunde:
var cabDetailListsBySequence = cabDetailsBySequence.ToDictionary(i=>i.Key, i=>i.ToList());
// foreach (var c in this.CABCodes) {
// c.Details = cabDetailListsBySequence[c.Sequence];
// }
this.CABCodes.AsParallel().ForAll(c=>c.Details = cabDetailListsBySequence[c.Sequence]);
Linq ist nicht immer so schnell wie eigene Schleifen mit if / else-Anweisungen zu schreiben. Die zweite Sache ist, dass ToList () eine neue Instanz einer Liste erstellt, die auch Ihre Performance verlangsamt.
Wie ist die Leistung mit diesem Code:
foreach (var c in this.CABCodes)
{
var detailList = new List<CABDetail>();
foreach(var d in CAPDetails)
{
if (d.CABSquence == c.Sequence)
{
detailList.Add(d);
}
}
c.Details = detailList;
}
vielleicht habe ich ein paar fehler im code gemacht, weil ich on-the-fly geschrieben habe.