【问题标题】:How to remove item from list in C#?如何从 C# 中的列表中删除项目?
【发布时间】:2012-04-04 20:44:09
【问题描述】:

我有一个列表存储在 resultlist 中,如下所示:

var resultlist = results.ToList();

看起来像这样:

ID FirstName  LastName
-- ---------  --------
1  Bill       Smith
2  John       Wilson
3  Doug       Berg

如何从列表中删除 ID 2?

【问题讨论】:

    标签: c# list


    【解决方案1】:

    List<T> 有两种方法可供您使用。

    RemoveAt(int index)如果你知道项目的索引就可以使用。例如:

    resultlist.RemoveAt(1);
    

    或者你可以使用Remove(T item):

    var itemToRemove = resultlist.Single(r => r.Id == 2);
    resultList.Remove(itemToRemove);
    

    当您不确定该项目是否真的存在时,您可以使用SingleOrDefault。如果没有项目,SingleOrDefault 将返回 nullSingle 将在找不到项目时抛出异常)。当存在重复值时两者都会抛出(两个项目具有相同的id)。

    var itemToRemove = resultlist.SingleOrDefault(r => r.Id == 2);
    if (itemToRemove != null)
        resultList.Remove(itemToRemove);
    

    【讨论】:

    • 好吧,也许比var itemsToRemove = resultlist.Where(r => r.Id == 2); foreach (var itemToRemove in ItemsToRemove) resultList.Remove(itemToRemove);
    • 不应该是resultlist.Items.RemoveAt(1);吗?
    【解决方案2】:

    简答:
    删除(从列表results

    results.RemoveAll(r => r.ID == 2); 将删除 results(原位)中具有 ID 2 的项目。

    过滤器(不从原始列表中删除results):

    var filtered = result.Where(f => f.ID != 2); 返回除具有 ID 2

    的项目之外的所有项目

    详细回答:

    我认为 .RemoveAll() 非常灵活,因为您可以拥有要删除的项目 ID 列表 - 请参考以下示例。

    如果你有:

    class myClass {
        public int ID; public string FirstName; public string LastName;
    }
    

    并将一些值分配给results,如下所示:

    var results = new List<myClass> {
        new myClass { ID=1, FirstName="Bill", LastName="Smith" },   // results[0]
        new myClass { ID=2, FirstName="John", LastName="Wilson" },  // results[1]
        new myClass { ID=3, FirstName="Doug", LastName="Berg" },    // results[2]
        new myClass { ID=4, FirstName="Bill", LastName="Wilson" }   // results[3]
    };
    

    然后您可以定义要删除的 ID 列表:

    var removeList = new List<int>() { 2, 3 };
    

    只需使用它来删除它们:

    results.RemoveAll(r => removeList.Any(a => a==r.ID));
    

    它将删除项目 2 和 3 并保留项目 1 和 4 - 如 removeList 所指定。 请注意这发生在适当的位置,因此不需要额外的分配。

    当然,您也可以将其用于单个项目,例如:

    results.RemoveAll(r => r.ID==4);
    

    在我们的示例中,它将删除 ID 为 4 的 Bill。

    最后要提到的是列表有一个索引器,也就是说,它们也可以像动态数组一样被访问,即results[3]会给你结果列表中的第4个元素(因为第一个元素有索引0,第二个有索引 1 等等)。

    因此,如果您想删除名字与结果列表的第 4 个元素相同的所有条目,您可以简单地这样做:

    results.RemoveAll(r => results[3].FirstName == r.FirstName);
    

    请注意,之后,只有 John 和 Doug 将保留在列表中,Bill 被删除(示例中的第一个和最后一个元素)。重要的是列表会自动收缩,因此它只剩下 2 个元素 - 因此在此示例中执行 RemoveAll 后允许的最大索引为 1
    (即results.Count() - 1)。

    一些琐事:您可以使用这些知识并创建本地函数

    void myRemove()  { var last = results.Count() - 1; 
                       results.RemoveAll(r => results[last].FirstName == r.FirstName); }
    

    如果你调用这个函数两次,你认为会发生什么? 喜欢

    myRemove(); myRemove(); 
    

    第一次调用将删除位于第一个和最后一个位置的 Bill,第二次调用将删除 Doug,并且只有 John Wilson 留在列表中。


    注意:由于C# Version 8,你也可以写results[^1]而不是var last = results.Count() - 1;results[last]

    void myRemove()  =>  results.RemoveAll(r => results[^1].FirstName == r.FirstName); 
    

    因此您不再需要局部变量last(请参阅indices and ranges)。此外,由于它是单行的,因此您不需要花括号,可以使用 =&gt; 代替。 有关 C# 中所有新功能的列表,请查看 here


    DotNetFiddle:Run the demo

    【讨论】:

      【解决方案3】:
      resultList = results.Where(x=>x.Id != 2).ToList();
      

      有一个我喜欢的小 Linq 助手,它易于实现,并且可以使带有“where not”条件的查询更易于阅读:

      public static IEnumerable<T> ExceptWhere<T>(this IEnumerable<T> source, Predicate<T> predicate)
      {
          return source.Where(x=>!predicate(x));
      }
      
      //usage in above situation
      resultList = results.ExceptWhere(x=>x.Id == 2).ToList();
      

      【讨论】:

      • 另一种类似的方法(使用谓词)是使用List.FindIndex/List.RemoteAt(它具有作为变异操作的“好”或“不太好”的特性)。跨度>
      • 是的,但要小心说 List 的操作 正在 变异。 List 在幕后使用数组,它可以在认为有必要时重新创建具有更小或更大容量的数组。 通常,移除是现有数组的就地突变。
      • 这不是线程安全的,为了简单起见,您可以使用 SingleOrDefault,它不需要包含在静态方法中
      • 没有人说它是线程安全的(它是否是线程安全的取决于线程应该做什么;实际上,给工作线程一个不同的内存结构可能比让它们都在一个并发集合上工作),并且 OP 希望所有记录 除了 与谓词匹配的记录,因此 SingleOrDefault 实际上会准确返回他们 想要的. “静态方法”实际上是一种扩展方法,就像大多数 Linq 一样,只要你不想要的东西(一个或多个)比你做的更容易定义,它就可以工作。
      【解决方案4】:

      你不指定是什么类型的列表,但是泛型 List 可以使用RemoveAt(index) 方法,也可以使用Remove(obj) 方法:

      // Remove(obj)
      var item = resultList.Single(x => x.Id == 2);
      resultList.Remove(item);
      
      // RemoveAt(index)
      resultList.RemoveAt(1);
      

      【讨论】:

        【解决方案5】:

        更简化:

        resultList.Remove(resultList.Single(x => x.Id == 2));
        

        无需创建新的 var 对象。

        【讨论】:

          【解决方案6】:

          还有另一种方法。它使用List.FindIndexList.RemoveAt

          虽然我可能会使用 KeithS 提供的解决方案(只是简单的 Where/ToList),但这种方法的不同之处在于它改变原始列表对象.这可能是一个好的(或坏的)“功能”,具体取决于预期。

          在任何情况下,FindIndex(加上保护)确保RemoveAt 在 ID 有间隙或排序错误等情况下是正确的,并且使用 RemoveAt(与 Remove ) 避免在列表中进行 O(n) 搜索。

          这是LINQPadsn-p:

          var list = new List<int> { 1, 3, 2 };
          var index = list.FindIndex(i => i == 2); // like Where/Single
          if (index >= 0) {   // ensure item found
              list.RemoveAt(index);
          }
          list.Dump();        // results -> 1, 3
          

          编码愉快。

          【讨论】:

            【解决方案7】:

            ...如果您确切知道索引,则只需 resultlist.RemoveAt(1)

            【讨论】:

              【解决方案8】:
              {
                  class Program
                  {
                      public static List<Product> list;
                      static void Main(string[] args)
                      {
              
                          list = new List<Product>() { new Product() { ProductId=1, Name="Nike 12N0",Brand="Nike",Price=12000,Quantity=50},
                               new Product() { ProductId =2, Name = "Puma 560K", Brand = "Puma", Price = 120000, Quantity = 55 },
                               new Product() { ProductId=3, Name="WoodLand V2",Brand="WoodLand",Price=21020,Quantity=25},
                               new Product() { ProductId=4, Name="Adidas S52",Brand="Adidas",Price=20000,Quantity=35},
                               new Product() { ProductId=5, Name="Rebook SPEED2O",Brand="Rebook",Price=1200,Quantity=15}};
              
              
                          Console.WriteLine("Enter ProductID to remove");
                          int uno = Convert.ToInt32(Console.ReadLine());
                          var itemToRemove = list.Find(r => r.ProductId == uno);
                          if (itemToRemove != null)
                              list.Remove(itemToRemove);
                          Console.WriteLine($"{itemToRemove.ProductId}{itemToRemove.Name}{itemToRemove.Brand}{itemToRemove.Price}{ itemToRemove.Quantity}");
                          Console.WriteLine("------------sucessfully Removed---------------");
              
                          var query2 = from x in list select x;
                          foreach (var item in query2)
                          {
                              /*Console.WriteLine(item.ProductId+" "+item.Name+" "+item.Brand+" "+item.Price+" "+item.Quantity );*/
                              Console.WriteLine($"{item.ProductId}{item.Name}{item.Brand}{item.Price}{ item.Quantity}");
                          }
              
                      }
              
                  }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-07-19
                • 2016-03-12
                相关资源
                最近更新 更多