Entfernen Sie das Element basierend auf der Bedingung aus der Liste

77

Ich habe eine Struktur wie diese:

public struct stuff
{
    public int ID;
    public int quan;
}

und möchte das Produkt entfernen, wo IDist 1.
Ich versuche dies derzeit:

prods.Remove(new stuff{ prodID = 1});

und es funktioniert nicht.

DANK AN ALLE

Nur Schatten
quelle

Antworten:

64

Verwenden von linq:

prods.Remove( prods.Single( s => s.ID == 1 ) );

Vielleicht möchten Sie sogar verwenden SingleOrDefault()und prüfen, ob das Element überhaupt vorhanden ist ...

EDIT:
Da stuffes sich um eine Struktur handelt, SingleOrDefault()wird nicht null zurückgegeben. Es wird jedoch default (stuff) zurückgegeben , das eine ID von 0 hat. Wenn Sie für Ihre normalen stuff-Objekte keine ID von 0 haben, können Sie diese ID abfragen:

var stuffToRemove = prods.SingleOrDefault( s => s.ID == 1 )
if( stuffToRemove.ID != 0 )
{
    prods.Remove( stuffToRemove );
}
Tanascius
quelle
Ziemlich sicher, dass Remove (null) eine Ausnahme auslöst, die SingleOrDefault dort ausschließt, wo es sich befindet.
Matt Mitchell
1
@ Graphain: Ich habe ein Beispiel für Sie hinzugefügt
Tanascius
Oder vielleicht besser lesbar if (stuffToRemove != default(stuff)).
Rufus L
207

Wenn Ihr Sammlungstyp a ist List<stuff>, ist der beste Ansatz wahrscheinlich der folgende:

prods.RemoveAll(s => s.ID == 1)

Dies führt nur einen Durchgang (Iteration) über die Liste durch und sollte daher effizienter sein als andere Methoden.

Wenn Ihr Typ allgemeiner ist ICollection<T>, kann es hilfreich sein, eine kurze Erweiterungsmethode zu schreiben, wenn Sie Wert auf Leistung legen. Wenn nicht, würden Sie wahrscheinlich mit LINQ (Anruf Whereoder Single) davonkommen .

Noldorin
quelle
5
Diese Antwort kann nicht akzeptiert werden, da IList nicht über RemoveAll verfügt. Der Themenstarter gibt nicht an, was er / sie hat: Liste <T> oder IList <T>.
Evgeni Nabokov
5
"Kann nicht"? Haha. Sei nicht pedantisch. Selbst wenn der Autor mit einer IList arbeitet, ist die Implementierung von RemoveAll ziemlich trivial.
Noldorin
5

Wenn Sie LINQ haben:

var itemtoremove = prods.Where(item => item.ID == 1).First();
prods.Remove(itemtoremove)
Nathan W.
quelle
Sie können Ihre whereAbfrage als Parameter zu First ()
Matt Mitchell
Oder Sie können einfach ersetzen WheremitFirst
Rufus L
3
prods.Remove(prods.Find(x => x.ID == 1));
Alex
quelle
0

prods.Remove(prods.Single(p=>p.ID == 1));

Sie können die Sammlung in foreach nicht ändern, wie Vincent vorschlägt

Kikaimaru
quelle
Single wäre langsamer als zuerst, aber es garantiert, dass Sie keine doppelten Produkte für dieselbe ID haben, nach denen Sie möglicherweise suchen möchten.
Matt Mitchell
0

Sie können nur etwas entfernen, auf das Sie einen Verweis haben. Sie müssen also die gesamte Liste durchsuchen:

stuff r;
foreach(stuff s in prods) {
  if(s.ID == 1) {
      r = s;
      break;
  }
}
prods.Remove(r);

oder

for(int i = 0; i < prods.Length; i++) {
    if(prods[i].ID == 1) {
        prods.RemoveAt(i);
        break;
    }
}
Vincent McNabb
quelle
Ist es nicht schneller, die Funktion find oder findIndex für eine Liste zu verwenden, als sie zu durchlaufen?
Rob
1
Sie können die Sammlung, die Sie iterieren, nicht ändern
Matt Mitchell
@Rob, für eine Liste sollte find gleich sein.
Matt Mitchell
@ Graphain oops. @Rob, ja ein Fund ist wahrscheinlich besser.
Vincent McNabb
0

Hier ist eine Lösung für diejenigen, die sie mit Entity Framework aus der Datenbank entfernen möchten :

prods.RemoveWhere(s => s.ID == 1);

Und die Erweiterungsmethode selbst:

using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;

namespace LivaNova.NGPDM.Client.Services.Data.Extensions
{
    public static class DbSetExtensions
    {
        public static void RemoveWhere<TEntity>(this DbSet<TEntity> entities, Expression<Func<TEntity, bool>> predicate) where TEntity : class
        {
            var records = entities
                .Where(predicate)
                .ToList();
            if (records.Count > 0)
                entities.RemoveRange(records);
        }
    }
}

PS Dies simuliert die Methode RemoveAll(), die für DB-Sets des Entity Frameworks nicht verfügbar ist.

Nur Schatten
quelle
-2

Sie könnten Linq verwenden.

var prod = from p in prods
           where p.ID != 1
           select p;
Chris
quelle
Dadurch wird das Objekt nicht entfernt. Wenn Sie zuweisen, als wären prods = prods.Where(p != 1).ToList()Sie näher dran, ändert dies jedoch nichts an einer Liste, die Sie als Parameter erhalten haben.
Matt Mitchell