【问题标题】:Lambda or LinQ expression to remove certain objects from List用于从列表中删除某些对象的 Lambda 或 LinQ 表达式
【发布时间】:2011-10-06 04:41:56
【问题描述】:

我有一个 cart.Lines 列表,想删除数量 == 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 循环中删除,得到错误: 收藏已修改;枚举操作可能无法执行。

我现在已经设法用这段代码做到了,肯定有更有效的东西吗?

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

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

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

【问题讨论】:

  • 看起来 ToList()/RemoveAll() 组合甚至可能是最有效的......(见下面的时间安排),但几乎没有。否定条件下的 Where() 后跟 ToList() 几乎一样快。我认为 RemoveAll() 对 List 进行了非常优化,因此它非常快,而其他 Linq 方法使用迭代器(yield return)往往会慢一些。

标签: c# asp.net linq lambda


【解决方案1】:

如果 Lines 是List&lt;T&gt;,那么最简单的方法就是直接写:

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

不过,如果 Lines 是 IEnumerable&lt;T&gt;,您可以选择否定项(如 Vlad 建议的那样) - 您也可以使用 ToList() 更改为列表,然后执行 RemoveAll(),但这将是多余的。

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

更新:

既然你说 Lines 是 IList&lt;T&gt;,那么你会想要选择否定并转换为如下列表:

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

或者您可以使用ToList() 转换为List&lt;T&gt;,然后调用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 毫秒

【讨论】:

    【解决方案2】:

    假设 cart.Lines 是 List:cart.Lines.RemoveAll(x =&gt; x.Quantity == 0);

    【讨论】:

    • 所以使用cart.Lines = cart.Lines.Where(x =&gt; x.Quantity &gt; 0).ToList()
    • @LaserBeak - 为什么你使用接口集合而不是通用列表集合?
    • @Ramhound,他可能正试图将实现与接口分离。许多代码分析工具倾向于建议直接使用 IList 或 ICollection 而不是 List。并不是说这一定是好是坏,只是经常出现的事情。是的,他在编辑中添加了 IList 说明。
    【解决方案3】:

    这些查询本质上是遍历一个列表,如您所知,您不应该使用它们直接修改列表。相反,您应该使用查询列出要删除的项目,然后在单独的操作中删除它们。

    编辑:

    是的,我忘了你可以在一行中使用 RemoveAll 来做到这一点:D

    【讨论】:

      【解决方案4】:
      var myResult = cart.Lines.Where(x => x.Quantity > 0)
      

      您也可以使用RemoveAll

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

      查看这篇回答您问题的帖子C# using LINQ to remove objects within a List

      【讨论】:

        【解决方案5】:

        我会继续发布我对这个问题的建议。

        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;   
        

        【讨论】:

          【解决方案6】:

          你可以这样做:

          Cart cart = new Cart();
          List<CartLine> cartLines = cart.Lines.ToList<CartLine>();
          cartLines.RemoveAll(x => x.Quantity == 0);
          cart.Lines = cartLines;
          

          此外,您应该将 CartLine Quantity 和 Product 属性设置为公开。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-08-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-20
            • 2012-04-24
            • 2015-05-21
            相关资源
            最近更新 更多