根据条件从列表中删除项

我有一个这样的结构:

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

并希望删除其中 ID为1的产品。
我现在正在尝试:

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

但是没有用。

谢谢大家

171094 次浏览

You can only remove something you have a reference to. So you will have to search the entire list:

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

or

for(int i = 0; i < prods.Length; i++) {
if(prods[i].ID == 1) {
prods.RemoveAt(i);
break;
}
}

Using linq:

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

Maybe you even want to use SingleOrDefault() and check if the element exists at all ...

EDIT:
Since stuff is a struct, SingleOrDefault() will not return null. But it will return default( stuff ), which will have an ID of 0. When you don't have an ID of 0 for your normal stuff-objects you can query for this ID:

var stuffToRemove = prods.SingleOrDefault( s => s.ID == 1 );
if( stuffToRemove.ID != 0 )
{
prods.Remove( stuffToRemove );
}

If you have LINQ:

var itemtoremove = prods.Where(item => item.ID == 1).First();
prods.Remove(itemtoremove)

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

you can't modify collection in foreach, as Vincent suggests

You could use Linq.

var prod = from p in prods
where p.ID != 1
select p;

If your collection type is a List<stuff>, then the best approach is probably the following:

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

This only does one pass (iteration) over the list, so should be more efficient than other methods.

If your type is more generically an ICollection<T>, it might help to write a short extension method if you care about performance. If not, then you'd probably get away with using LINQ (calling Where or Single).

prods.Remove(prods.Find(x => x.ID == 1));

Here is a solution for those, who want to remove it from the database with Entity Framework:

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

And the extension method itself:

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);
}
}
}


P.S. This simulates the method RemoveAll() that's not available for DB sets of the entity framework.

A bit late to the game, however, a simple extension method can implement a RemoveAll on IList<T>. The trick is to loop over the collection in reverse order to avoid the extra logic of deleting the current item and having to try on the current index if removed. Also the reverse order prevents having to copy all the remaining items. Depending on the .NET version, this copy could be expensive.

    public static int RemoveAll<T>(this IList<T> list, Predicate<T> match)
{
if (list == null) throw new ArgumentNullException("list");
if (match == null) throw new ArgumentNullException("match");


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