从 vb.net 中的列表中删除项目失败

发布于 2024-08-15 15:43:34 字数 223 浏览 6 评论 0原文

我有一个通用列表,我正在使用 List.Remove(Object) 删除其中的项目。我一直在删除项目,但每当我到达第五个项目时,我删除它都会失败,并且不会将其从列表中删除。我要删除的内容似乎并不重要,但每次我尝试删除五个项目时,第五个项目都会失败。

可能是什么原因造成的?查看 List(Of T).Remove 的文档,它没有指定他们使用什么算法来删除该项目。

I have a generic list that I'm removing items out of using List.Remove(Object). I have been removing items but whenever I get to the fifth item I'm removing it fails and does not remove it from the list. It doesn't seem to matter what I'm removing but everytime I try to remove five items it fails on the fifth item.

What could be causing this? Looking at the documentation for List(Of T).Remove, it doesn't specify what algorithm they're using to remove the item.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

人海汹涌 2024-08-22 15:43:34

Remove 将根据对对象调用 .Equals 进行匹配。默认情况下,对于给定对象,它只会匹配相同对象。如果您希望具有相同属性的两个对象被视为相等,即使它们不是同一个对象,您需要重写 Equals 方法并将逻辑放在那里。

不过,另一个不错的选择是使用 RemoveAll 并传入匿名委托或带有您要查找的条件的 lambda 表达式。例如:

customers.RemoveAll(customer => customer.LastName.Equals(myCustomer.LastName));

当然,只有当您确实想要删除所有匹配项,和/或如果您确定只有一个匹配项时,这才有效。

Remove is going to match based on calling .Equals on your objects. By default for a given object it'll only match the same object. If you want two objects with the same properties to be considered equal even if they're not the same object, you need to override the Equals method and put your logic there.

However, another good option is to use RemoveAll and pass in an anonymous delegate or a lambda expression with the criteria you're looking for. E.g.:

customers.RemoveAll(customer => customer.LastName.Equals(myCustomer.LastName));

Of course that only works if you really want to remove all the matching items, and/or if you're certain there will only be one that matches.

浮华 2024-08-22 15:43:34

如果您使用基于索引的方法从列表中删除项目,请记住,当您删除之前的项目时,您删除的项目后面的项目索引将更改 -1。

If you are using an indexed based method to remove items from the list and remember that the indexes of items after the one you remove will change by -1 as you remove the ones before it.

作死小能手 2024-08-22 15:43:34

您的清单中有多少项目?你如何删除它们,只是循环?请记住这些是从 0 开始的列表。如果您正在使用整数执行任何类型的 For 循环,则在删除项目时它可能无法工作。

How many items are in your list? How are you removing them, just looping through? Keep in mind these are 0-based lists. If you're doing any sort of For loop with an integer it may not work as you're removing items.

终弃我 2024-08-22 15:43:34

作为一般规则,您不应修改正在循环的集合,而只能修改该集合内的项目。删除 foreach 循环内的项目的问题在于,它会更改正在循环的集合并干扰列表计数和迭代位置。

常见的解决方案是:

  1. 向后循环集合,以便迭代器的干扰不会影响执行
  2. 创建一个新集合,以便您可以修改一个集合并循环另一个集合。

向后循环:

这是一个接受 Collection(Of T) 的扩展方法(您可以使用 List(Of T),但列表类已经公开了 RemoveAll 方法基本上做同样的事情)。
我们将向后循环并根据传入的 lambda 函数检查集合中每个项目的有效性。如果匹配,我们将删除它。

<Extension()>
Public Sub RemoveEach(Of T)(ByRef col As Collection(Of T),
                            ByVal match As Func(Of T, Boolean))
    For i = col.Count - 1 To 0 Step -1
        If match(col(i)) Then col.RemoveAt(i)
    Next
End Sub

然后像这样使用:

Dim col = New Collection(Of Integer)({1, 2, 3, 4}.ToList)
col.RemoveEach(Function(i) (i Mod 2) = 0)
'Produces list of 1 & 3

创建新集合:

使用 RemoveAt 来跟踪集合索引并删除项目会更有效,而不是使用 Remove 来获取一个对象,然后检查与该对象匹配的集合的其余部分。但是,如果您确实想要一种方法来处理删除 For 循环中的项目,您可以在原始集合上调用 ToList ,从而创建一个新列表。然后,您可以循环新列表以查找需要从原始列表中删除的项目。每当您找到一个对象时,您都可以安全地将其从原始集合中删除,因为它当前尚未被枚举。

<Extension()>
Public Sub RemoveEachObject(Of T)(ByRef col As Collection(Of T), 
                                  ByVal match As Func(Of T, Boolean))
    For Each o As T In col.ToList()
        If match(o) Then col.Remove(o)
    Next
End Sub

如需了解更多信息,请查看从“foreach”循环中的列表中删除的答案

As a general rule, you should not modify a collection that your are looping over, only the items inside of that collection. The problem with removing items inside of a for each loop is that it changes the collection that is being looped and interferes with the list count and iteration location.

Common solutions are to:

  1. Loop through the collection backwards so interferences with the iterator won't impact the execution
  2. Create a new collection so you can modify one collection and loop over another.

Loop Backwards:

Here's an extension method that takes in a Collection(Of T) (you could use a List(Of T), but the list class already exposes a RemoveAll method which basically does this same thing).
We'll loop backwards and check the validity of each item in the collection based on the passed in lambda function. If it matches, then we'll remove it.

<Extension()>
Public Sub RemoveEach(Of T)(ByRef col As Collection(Of T),
                            ByVal match As Func(Of T, Boolean))
    For i = col.Count - 1 To 0 Step -1
        If match(col(i)) Then col.RemoveAt(i)
    Next
End Sub

Then use like this:

Dim col = New Collection(Of Integer)({1, 2, 3, 4}.ToList)
col.RemoveEach(Function(i) (i Mod 2) = 0)
'Produces list of 1 & 3

Create New Collection:

It is more efficient to keep track of the collection index and remove items using RemoveAt instead of Remove which takes an object and then checks the rest of the collection for matches against that object. However, if you really wanted a way to process removing items within a For Loop, you could call ToList on the original collection, thereby creating a new list. Then, you can loop over the new list to find items that need to be removed from the original. Whenever you find an object, you can safely remove it from the original collection, because it is not currently being enumerated over.

<Extension()>
Public Sub RemoveEachObject(Of T)(ByRef col As Collection(Of T), 
                                  ByVal match As Func(Of T, Boolean))
    For Each o As T In col.ToList()
        If match(o) Then col.Remove(o)
    Next
End Sub

For more info, check out this great answer to Remove from a List within a 'foreach' loop.

如果你使用for循环来删除元素,你应该考虑使用foreach,它更适合集合、列表和可数对象

If you are using for loop to remove elements, you should consider using the foreach, it is more suitable for collections, lists and numerable objects

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文