2013-05-17 17 views
8

Wie Verwenden von LINQ, um bestimmte Elemente aus einem IList basierend auf einem anderen IList zu entfernen. Ich muss Datensätze aus list1 entfernen, wo ID in list2 vorhanden ist. Unten ist das CodebeispielLINQ zum Entfernen bestimmter Elemente aus einem IList <T> basierend auf einem IList <int>

class DTO 
{ 

    Prop int ID, 
    Prop string Name 
} 

IList<DTO> list1; 

IList<int> list2; 



foreach(var i in list2) 
{ 
    var matchingRecord = list1.Where(x.ID == i).First(); 
    list1.Remove(matchingRecord); 
} 

Dies ist, wie ich es tue, gibt es einen besseren Weg, das gleiche zu tun.

+6

Es gibt keinen Tag ohne eine ähnliche Frage. –

+0

Verwenden Sie nicht Linq für dieses. Bei Linq geht es darum, neue Sequenzen zu filtern und zu erstellen, Sammlungen nicht zu verändern. –

Antwort

8

können Sie verwenden Where für einfacher:

list1 = list1.Where(x => !list2.Contains(x.ID)) 
      .ToList(); 

Aber Sie müssen wirklich an seinem Platz entfernen, lieber @ DanielHilgarth Antwort

+3

RemoveAll gibt keine Liste zurück, sondern gibt einen Int zurück, der die Anzahl der gelöschten Elemente angibt. –

+0

@RobertJ .: Bearbeitete meine Antwort –

+0

@RobertJ. Sie sollten RemoveAll verwenden, siehe meine Antwort –

12

ich diesen Ansatz verwenden würde:

var itemsToRemove = list1.Where(x => list2.Contains(x.ID)).ToList(); 
foreach(var itemToRemove in itemsToRemove) 
    list1.Remove(itemToRemove); 

Dieser Ansatz entfernt die Gegenstände an Ort und Stelle. Es wird am besten für Fälle verwendet, in denen viele Elemente in list1 und wenige in list2 sind.
Wenn die Anzahl der Artikel in list1 und list2 ähnlich ist, ist der Ansatz von Cuong Le eine gute Alternative.

+1

Warum eine 'ToList()' nach dem 'Where'? Glaube nicht, dass das nötig ist. –

+2

@GeorgeDuckett: Ja, es ist erforderlich. Andernfalls iteriert "itemsToRemove" über "list1". Zusammen mit dem 'Remove' würde dies eine' InvalidOperationException' ergeben: * Collection wurde modifiziert; Enumerationsoperation kann nicht ausgeführt werden * –

+0

Ahh, guter Punkt, vergaß das. –

11

Sie könnten eine "RemoveAll()" - Erweiterungsmethode für IList<T> schreiben, die genau wie List.RemoveAll() funktioniert. (Dies ist genug allgemein nützlich in einer gemeinsamen Klassenbibliothek zu halten.)

Zum Beispiel (Fehler der Klarheit halber entfernt prüfen; Sie müssen die Parameter nicht null überprüfen):

public static class IListExt 
{ 
    public static int RemoveAll<T>(this IList<T> list, Predicate<T> match) 
    { 
     int count = 0; 

     for (int i = list.Count - 1; i >= 0; i--) 
     { 
      if (match(list[i])) 
      { 
       ++count; 
       list.RemoveAt(i); 
      } 
     } 

     return count; 
    }   

Dann Die Elemente aus list1 nach Bedarf zu entfernen würde in der Tat so einfach werden wie:

list1.RemoveAll(item => list2.Contains(item.ID)); 
Verwandte Themen