【问题标题】:Remove an item from an IEnumerable<T> collection从 IEnumerable<T> 集合中删除项目
【发布时间】:2012-12-18 01:59:02
【问题描述】:

我有一个填充的 IEnumerable&lt;User&gt; 集合。

我想从中删除一个项目,我该怎么做?

foreach(var u in users)
{
  if(u.userId = 1123)
  {
    // remove!
  }
}

我知道您不打算在循环时删除,所以我不介意创建一个新集合或在之后删除它。

但我不知道如何删除一个项目,因为某种原因有点丢失了!

另外,我也很困惑,我怎样才能创建一个新的集合,例如:

IEnumerable<User> modifiedUsers = new List<User>();

foreach(var u in users)
{
   if(u.userId != 1233)
   {
        modifiedUsers.add ??????
   }
}

如何添加到集合中?

【问题讨论】:

  • 顺便说一句,在迭代列表时,您无法删除元素而不会出现运行时错误。就像 Tilak 在他的回答中显示的那样,必须在枚举之前复制列表。

标签: c# ienumerable


【解决方案1】:

不删除,而是创建一个新的List,而不使用 LINQ:

// remove
users = users.Where(u => u.userId != 123).ToList();

// new list
var modified = users.Where(u => u.userId == 123).ToList();

【讨论】:

  • 您在这两种情况下都在创建一个新列表。第一个示例只是覆盖了引用。
  • 您的术语不正确。您没有从列表中删除项目,在这两个示例中,您都创建了一个新列表,而旧列表不受影响。您只是在第一个示例中覆盖了引用,因此声明它导致 remove 是不正确的。您应该更新您的问题以澄清这一点。
  • 显然标题和作者想要删除该项目,而不是创建一个没有它的新列表......
  • 虽然这对我很有用,但我只想指出作者要求从 IEnumerable 中删除项目,因此示例中的后缀“.ToList()”不是必需的。 (虽然可能是很多最终访问此页面的人所追求的。)
  • 始终使用AsList() 而不是ToList()
【解决方案2】:

您不能从IEnumerable 中删除项目;它只能被枚举,如此处所述: http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.aspx

如果您想添加和删除项目,您必须使用ICollection。也许你可以尝试投射你的IEnumerable;当然,这只有在底层对象实现 ICollection` 时才有效。

更多关于ICollection的信息: http://msdn.microsoft.com/en-us/library/92t2ye13.aspx

您当然可以从您的 IEnumerable 中创建一个新列表,正如 lante 所指出的那样,但这可能是“次优的”,当然,这取决于您的实际用例。

ICollection 可能是要走的路。

【讨论】:

    【解决方案3】:

    尝试将IEnumerable 变成List。从此时起,您将能够使用ListRemove 方法来删​​除项目。

    要将其作为参数传递给使用 Linq 的 Remove 方法,您可以通过以下方法获取项目:

    • users.Single(x =&gt; x.userId == 1123)
    • users.First(x =&gt; x.userId == 1123)

    代码如下:

    users = users.ToList(); // Get IEnumerable as List
    
    users.Remove(users.First(x => x.userId == 1123)); // Remove item
    
    // Finished
    

    【讨论】:

    • 但我可以将它分配给需要可枚举的后记的东西吗?我必须重新开始吗?
    • @user1361315 当然,List 实现了 IEnumerable,因此您确实可以将其分配给 IEnumerable
    【解决方案4】:

    你不能。 IEnumerable&lt;T&gt; 只能迭代。

    在您的第二个示例中,您可以通过迭代其副本从原始集合中删除

    foreach(var u in users.ToArray()) // ToArray creates a copy
    {
       if(u.userId != 1233)
       {
            users.Remove(u);
       }
    }
    

    【讨论】:

      【解决方案5】:

      你可以这样做:

      users = users.Where(x => x.userId != userIdToRemove);
      

      【讨论】:

        【解决方案6】:

        IEnumerable 接口就是这样,可枚举的 - 它不提供任何方法到 AddRemove 或根本修改列表。

        接口只是提供了一种迭代某些项目的方法——大多数需要枚举的实现都会实现IEnumerable,例如List&lt;T&gt;

        你为什么不直接使用你的代码而不用隐式转换为IEnumerable

        // Treat this like a list, not an enumerable
        List<User> modifiedUsers = new List<User>();
        
        foreach(var u in users)
        {
           if(u.userId != 1233)
           {
                // Use List<T>.Add
                modifiedUsers.Add(u);
           }
        }
        

        【讨论】:

        • 我必须修改它,然后将它传递给期望一个可枚举的东西。
        • 然后修改它并传递它 - 没有理由不能将 List&lt;T&gt; 传递给期望 IEnumerable&lt;T&gt; 的方法,因为 List&lt;T&gt; 派生自 IEnumerable&lt;T&gt;。由于协方差规则,我什至认为您不需要演员表。
        【解决方案7】:

        您不能删除IEnumerable&lt;T&gt; 元素,但可以使用Enumerable.Skip Method

        【讨论】:

          【解决方案8】:

          users.toList().RemoveAll(user => )

          【讨论】:

          • 由于 .ToList(),这会将您的整个列表放入内存。应该不惜一切代价避免这种情况
          【解决方案9】:

          现在有一个扩展方法可以将IEnumerable&lt;&gt; 转换为Dictionary&lt;,&gt;,然后再有一个Remove 方法。

          public readonly IEnumerable<User> Users = new User[]; // or however this would be initialized
          
          // To take an item out of the collection
          Users.ToDictionary(u => u.Id).Remove(1123);
          
          // To take add an item to the collection
          Users.ToList().Add(newuser);
          

          【讨论】:

            猜你喜欢
            • 2011-03-12
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2010-11-15
            • 2013-01-17
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多