2009-08-21 22 views
0

Ich verwende LINQ, um eine Baumstruktur von Objekten aus einer Sammlung von Objekten aufzubauen, die von einem Aufruf einer gespeicherten Prozedur abgerufen wurden.Linq Elemente aus einer Sammlung in eine andere Sammlung entfernen

Ich möchte wissen, ob
a) es eine Möglichkeit ist, die Elemente aus einer Sammlung zu einer neuen Kollektion
b) zu entfernen, wenn es klug tatsächlich jeder Punkt Leistung ist dies etwas dabei

mein Code sieht wie folgt:

class MyEntity 
{ 
    int ID { get; set; } 
    int? ParentID { get; set; } 
    string Name { get; set; } 
    List<MyEntity> children = new List<MyEntity>(); 
    List<MyEntity> Children { get { return children; } } 
} 

List<MyEntity> initialCollection = //get stuff from DB 

List<MyEntity> rootElements = (from e in initialCollection 
           where e.ParentID == null 
           select e).ToList(); 

List<MyEntity> childElements = (from e in initialCollection 
           where e.ParentID != null 
           select e).ToList(); 

foreach(MyElement e in rootElements) 
    e.Children.AddRange((from c in childElements 
         where c.ParentID == e.ID 
         select c).ToList()); 
//do some more recursion 

Also im Grunde; gibt es eine Möglichkeit, die select-Anweisung auszuführen, wobei ich die Elemente aus initialCollection tatsächlich entferne, während ich sie auswähle. Die Idee ist es, die Anzahl der zu durchsuchenden Elemente zu reduzieren, während ich meinen Baum rekursiv aufbaue. Würde es tatsächlich einen Vorteil dabei geben, oder ist der Aufwand, Elemente aus einer Sammlung zu entfernen und zu einer anderen hinzuzufügen, zu groß?

Antwort

3

Eine viel bessere Idee wäre, einen Lookup zu erstellen.

var childElements = initialCollection.Where(e => e.ParentID != null) 
            .ToLookup(e => e.ParentID); 

foreach (MyElement e in rootElements) 
{ 
    if (childElements.Contains(e.ID)) 
    { 
     e.Children.AddRange(childElements[e.ID]); 
    } 
} 

Ein Lookup ein bisschen wie ein Dictionary<TKey, IEnumerable<TValue>> ist - also im Grunde arbeiten Sie heraus, welche Kinder gehören zu welchem ​​Elternteil sie dann fügen Sie alle in

I denke, der Anruf an Contains ist notwendig, falls Sie irgendwelche Wurzelelemente ohne Kinder haben - ich würde erwarten, dass der Indexer eine Ausnahme auslöst, wenn der angegebene Schlüssel nicht existiert. Die Dokumente sind jedoch nicht sehr klar - sie können stattdessen eine leere Sequenz zurückgeben.

+0

Brilliant, eine wirklich schöne saubere Lösung dort. Prost. –

2

a) Ich glaube nicht, dass Sie das aus mehreren Gründen tun können. Erstens werden die linq-Operatoren zur Auswertung von Ausdrücken verwendet und beeinflussen somit nicht die Quellensammlung (en) (oder haben andere Nebeneffekte). Zweitens erlauben Iteratoren nicht, dass die Quellensammlung während der Iteration geändert wird, so dass es keine Möglichkeit gibt, Elemente während der Auswahl trotzdem zu entfernen.

b) Es ist unwahrscheinlich, dass dies einen Leistungsvorteil bringen würde - das Entfernen von Elementen aus einer Liste ist O (n), so dass m Elemente entfernt werden, was sehr langsam sein kann, wenn viele Elemente entfernt werden müssen. Wenn Sie nicht wirklich nach Speicherplatz gefragt werden, ist es besser, nur eine Kopie zu erstellen und diese zu verwenden, und in diesem Fall möchten Sie sowieso eine andere Datenstruktur haben.

Verwandte Themen