wake-up-neo.com

Instanzen mit LINQ oder Lambda aus einer Liste entfernen?

Jetzt komme ich zu einer Etappe, um alle meine Daten als Liste im Cache (Objekte) abzurufen. Als nächstes muss ich einige Instanzen aus der Liste entfernen.

Normalerweise würde ich so entfernen:

List<T> list;
List<T2> toBeRemovedItems;
// populate two lists
foreach(T2 item in toBeRemovedItems)
{
    list.Remove(delegate(T one) { 
        // build a condition based on item
        // return true or false
    });
}

Um genauer zu sein, baue ich die toBeRemvoedItems-Liste einer dynamischen Klasse (nicht einer formal definierten Klasse). Zum Beispiel ist die T-Klasse so etwas wie MyClass und die Codes zum Entfernen sind:

class MyClass<C> {
    public string Value1 { get; set; }
    public int Value2 { get; set; }
    public C ObjectC { get; set; }
}
....
List<MyClass<C>> list;
// populate list
// populate toBeRemovedItems. Here is an example of hard-coded codes:
var toBeRemovedLItems = new[] {
    new { Value1="a", Value2 = 1},
    new { Value2="x", Value2 = 10},
    ...
};
// toBeRemovedItems may be the result of Select from a collection
foreach(var item in toBeRemovedLItems)
{
    list.Remove(delegate(MyClass one) {
        return one.Value1 = item.Value1 && one.Value2 < item.Value2;
    });
}

Ich habe versucht, nach Remove()-Methode in IEnumerable-Schnittstelle von MSDN zu suchen, aber ich kann die Methode von Remove() dort nicht finden (es macht Sinn, dass IEnumerable nur für die Aufzählung verwendet wird). In der List-Klasse gibt es mehrere überladene Remove(...)-Methoden. Ich bin nicht sicher, ob es alternative Möglichkeiten gibt, Elemente mithilfe von LINQ- oder Lambda-Ausdrücken aus einer Liste zu entfernen.

Ich habe übrigens überlegt, wie Sie eine Abfrage mit einer Liste durchführen können, um eine Untermenge oder eine neue IEnumerable-Liste mit Where-Bedingungen abzurufen, ähnlich wie das Verschieben von Elementen aus einer Liste. Ich ziehe es jedoch vor, Elemente aus meiner zwischengespeicherten Liste zu entfernen, und in einigen Fällen kann ich die listeneigenschaft in einer Klasse nicht auf eine neue Liste zurücksetzen (z. B. private Gruppe).

27
David.Chu.ca

Sie können die Methode RemoveAll verwenden:

MyClass one; //initialize MyClass
list.RemoveAll(item => one.Value1 == item.Value1 && one.Value2 < item.Value2);
40
Francis B.

Sie können die Where-Methode von LINQ verwenden, um Werte herauszufiltern, die nicht Teil der Liste sein sollten. Das Ergebnis ist ein IEnumerable<T> mit entfernten Elementen. 

var res = list.Where(item => !(one.Value1 == item.Value1 && one.Value2 < item.Value2));

Dadurch wird die ursprüngliche List<T>-Instanz nicht aktualisiert, sondern ein neuer IEnumerable<T> mit entfernten Werten erstellt. 

21
JaredPar

Wenn ich die Frage richtig bekomme, erzeugt man aus zwei Listen einen eindeutigen Satz.

Hierfür können Sie Folgendes verwenden

Liste list1; Liste list2;

List list3 = list1.Except (list2)

Die Liste3 enthält eindeutige Elemente.

5
Bhaskar

Ich stimme Jareds Vorschlag zu, bestimmte Elemente herauszufiltern, aber es sieht so aus, als wäre eine join auf Value1 ein effizienter Ansatz:

var res = from item1 in list
          join item2 in toBeRemovedList
            on item1.Value1 equals item2.Value1
          where item1.Value2 >= item2.Value2
          select item1;

Update: Offenbar versage ich beim Leseverständnis - neuer Ansatz:

var removeDict = toBeRemovedList.ToDictionary(i => i.Value1, i => i.Value2);
list.RemoveAll(item => {
    int itemToRemoveValue2;
    if(removeDict.TryGetValue(item.Value1, out itemToRemoveValue2))
        return item.Value2 < itemToRemoveValue2;
    return false;
});

Natürlich wäre es noch besser, wenn Ihre zu entfernende Liste als Wörterbuch beginnen könnte. Letztendlich versuchen wir nur, unsere Übereinstimmung mit Value1 effizienter zu gestalten.

4
dahlbyk
foreach(var item in toBeRemovedLItems) {   
   list.RemoveAll(one => one.Value1 == item.Value1 && one.Value2 < item.Value2); 
}

Wieder zu spät. Naja.

2
Richard Hein

Bei Sammlungen, die keine Listen sind (RemoveAll kann nicht verfügbar gemacht werden), können Sie immer noch Elemente mit einem Einzeiler entfernen.

Um Inline zu ersetzen, generieren Sie einfach eine Liste der zu entfernenden Elemente, führen Sie sie durch und führen Sie den Code zum Entfernen aus.

var dictionary = new Dictionary<string, string>(){{"foo", "0"}, {"boo", "1"}, {"goo", "1"}};
dictionary
    .Where(where_item =>
        ((where_item.Key == "foo") && (where_item.Value == "0"))
        || ((where_item.Key == "boo") && (where_item.Value == "1"))
    )
    .ToList()
    .ForEach(remove_item => {
        dictionary.Remove(remove_item.Key);
    });

Um die Kopie zu ersetzen, generieren Sie einfach ein gefiltertes Aufzählungszeichen und geben Sie eine neue Kopie zurück.

var dictionary0 = new Dictionary<string, string>(){{"foo", "0"}, {"boo", "1"}, {"goo", "1"}};
var dictionary1 = dictionary0
    .Where(where_item =>
        ((where_item.Key == "foo") && (where_item.Value == "0"))
        || ((where_item.Key == "boo") && (where_item.Value == "1"))
    )
    .ToDictionary(each_item => each_item.Key, each_item => each_item.Value);
1
Alex

Vielleicht versuchen Sie so etwas zu tun?

List<T> firstList;
List<T2> toBeRemovedItems;
List<T> finalList;

foreach(T item in firstList)
{
    toBeRemovedItems = CheckIfWeRemoveThisOne(item.Number, item.Id);
    if (toBeRemovedItems == null && toBeRemovedItems.Count() == 0)
        finalList.Add(item);
}

So konnte ich ein Problem lösen, bei dem Duplikate zwischen einem List<ViewModel> und einem List<Model> entfernt wurden. Ich habe die Funktion CheckIfWeRemoveThisOne verwendet, um zu prüfen, ob der item.Number zu einem anderen Element gehörte, wobei die ID als definierendes Merkmal verwendet wurde. Wenn es ein anderes Objekt (ein Duplikat) gefunden hat, anstatt es zu versuchen und es aus der ursprünglichen Liste zu entfernen (was mir einen List<Model> zurückgegeben hat und ihm in der ersten Funktion ein List<ViewModel> gegeben wurde), hatte ich meine Zweifel, wie ich es tun sollte Ich könnte einfach eine neue Liste erstellen - füge das Ergebnis hinzu, falls es ok wäre.

0
vapcguy