从列表中删除某些对象的Lambda或LinQ表达式

3

我有一个购物车行列表,想要删除所有数量为0的项目。

这是一个保存CartLine对象集合的列表:

public class Cart
{
    private IList<CartLine> lines = new List<CartLine>();
    public IList<CartLine> Lines { get { return lines; } set { lines = value; } }
}   

public class CartLine
{
    Product Product {get; set;}
    int Quantity {get; set;}

}

所以类似于这样:

cart.Lines.RemoveAll(x => x.Quantity == 0)

我只能得到Remove和RemoveAt,没有RemoveAll!

在foreach循环中无法删除,会出现错误:Collection was modified; enumeration operation may not execute.

我现在已经用这段代码实现了,肯定还有更高效的方法吧?

var myList = cart.Lines.ToList();
myList.RemoveAll(x => x.Quantity == 0);
cart.Lines = myList;

好的,问题解决了!谢谢大家,这里就可以解决:

cart.Lines = cart.Lines.Where(x => x.Quantity != 0);

(该代码行为it技术相关内容)

看起来使用ToList() /RemoveAll()的组合可能是最有效的...(请参见下面的时间),但仅仅如此。负条件下的Where()接着使用ToList()也几乎同样快。我认为,RemoveAll()对于List<T>进行了非常优化,所以它在其他Linq方法使用迭代器(yield return)的情况下变得极其快速,这些方法往往会比较慢。 - James Michael Hare
6个回答

7
如果Lines是一个List<T>,那么最简单的方法就是这样写:
cart.Lines.RemoveAll(x => x.Quantity == 0);

如果Lines是一个IEnumerable,你可以选择负数(就像Vlad建议的那样),你也可以使用ToList()将其转换为列表,然后使用RemoveAll(),但这样做有些过度。
cart.Lines = cart.Lines.Where(x => x.Quantity != 0);

更新:

由于你说Lines是一个 IList<T>,那么你需要选择负数并将其转换为列表,如下所示:

cart.Lines = cart.Lines.Where(x => x.Quantity != 0).ToList();

或者您可以使用 ToList() 将其转换为 List<T>,然后调用 RemoveAll(),最后保存回去:

var temp = cart.Lines.ToList();
temp.RemoveAll(x => x.Quantity != 0);
cart.Lines = temp;

顺便提一下,我计时了构建删除列表和使用Remove()与选择负数使用Where()并调用ToList()的时间,结果是使用Where/ToList组合更快,这很有道理,因为两者都会分配内存,但Where/ToList的内存移动要少得多。

以下是从100,000个整数的列表中删除所有偶数的时间:

  • 构建删除列表并对每个数字调用Remove()所需的时间为:3921毫秒
  • 使用负数的Where(),然后使用ToList()删除所有偶数所需的时间为:2毫秒
  • 在原始列表上使用ToList(),然后使用RemoveAll()删除所有偶数所需的时间为:1毫秒

3
假设 cart.Lines 是 List<> 类型:cart.Lines.RemoveAll(x => x.Quantity == 0);

所以使用 cart.Lines = cart.Lines.Where(x => x.Quantity > 0).ToList() - treetey
@LaserBeak - 你为什么要使用接口集合而不是通用的List集合呢? - Security Hound
@Ramhound,他可能试图将实现与接口分离一些。许多代码分析工具倾向于建议使用IList<T>或ICollection<T>而不是直接使用List<T>。并不是说这是好还是坏,只是经常出现的事情。是的,他在编辑中添加了IList<T>的澄清。 - James Michael Hare

1

1

我将继续发布我的解决方案建议。

private IList<CartLine> lines = new List<CartLine>(); 

应该是:

private List<CartLine> lines = new List<CartLine>(); 

这将允许您使用建议的方法:

cart.Lines.RemoveAll(x => x.Quantity == 0);  

通过这种方式,您可以准确地做到这一点:

var myList = cart.Lines.ToList();       
myList.RemoveAll(x => x.Quantity == 0);              
cart.Lines = myList;   

1

这些查询实际上是在列表上进行循环,而且正如您所知,您不应该直接使用它们来修改列表。相反,您应该使用查询创建一个要删除的项目列表,然后在单独的操作中将它们删除。

编辑:

是的,我忘记你可以使用RemoveAll在一行代码中完成这个操作 :D


0
你可以按照以下的方式来做:
Cart cart = new Cart();
List<CartLine> cartLines = cart.Lines.ToList<CartLine>();
cartLines.RemoveAll(x => x.Quantity == 0);
cart.Lines = cartLines;

此外,您应将CartLine数量和产品属性设置为公共属性。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接