Vb.net 使用For Each循环遍历列表时删除列表中的项

Vb.net 使用For Each循环遍历列表时删除列表中的项,vb.net,list,loops,foreach,Vb.net,List,Loops,Foreach,我有一个名为NeededList的列表,我需要检查此列表中的每个项目,看看它是否存在于我的数据库中。如果它确实存在于数据库中,我需要将其从列表中删除。但是我不能在遍历列表时更改它。我怎样才能做到这一点 以下是我目前的代码: For Each Needed In NeededList Dim Ticker = Needed.Split("-")(0).Trim() Dim Year = Needed.Split("-")(1).Trim() Dim

我有一个名为
NeededList
的列表,我需要检查此列表中的每个项目,看看它是否存在于我的数据库中。如果它确实存在于数据库中,我需要将其从列表中删除。但是我不能在遍历列表时更改它。我怎样才能做到这一点

以下是我目前的代码:

For Each Needed In NeededList
        Dim Ticker = Needed.Split("-")(0).Trim()
        Dim Year = Needed.Split("-")(1).Trim()
        Dim Period = Needed.Split("-")(2).Trim()
        Dim Table = Needed.Split("-")(3).Trim()
        Dim dr As OleDbDataReader
        Dim cmd2 As New OleDb.OleDbCommand("SELECT * FROM " & Table & " WHERE Ticker = ? AND [Year] = ? AND Period = ?", con)
        cmd2.Parameters.AddWithValue("?", Ticker)
        cmd2.Parameters.AddWithValue("?", Year)
        cmd2.Parameters.AddWithValue("?", Period)
        dr = cmd2.ExecuteReader
        If dr.HasRows Then
            NeededList.Remove(Needed)
        End If
Next
不能使用
For Each
循环修改数组的内容(或任何其他可以用
For Each
快速枚举的内容)。您需要使用简单的
For
循环并迭代每个索引


提示:因为您将删除索引,我建议从最后一个索引开始,朝第一个索引前进,这样您就不会在每次删除索引时跳过一个。

您可以使用For循环在步骤-1中迭代每个索引

For i as Integer = NeededList.Count - 1 to 0 Step -1

    Dim Needed = NeededList(i)

    'this is a copy of your code
    Dim Ticker = Needed.Split("-")(0).Trim()
    Dim Year = Needed.Split("-")(1).Trim()
    Dim Period = Needed.Split("-")(2).Trim()
    Dim Table = Needed.Split("-")(3).Trim()

    Dim dr As OleDbDataReader
    Dim cmd2 As New OleDb.OleDbCommand("SELECT * FROM " & Table & " WHERE Ticker = ? AND [Year] = ? AND Period = ?", con)
    cmd2.Parameters.AddWithValue("?", Ticker)
    cmd2.Parameters.AddWithValue("?", Year)
    cmd2.Parameters.AddWithValue("?", Period)
    dr = cmd2.ExecuteReader

    'MODIFIED CODE
    If dr.HasRows Then NeededList.RemoveAt(i)

Next i

不,不能使用for-each,但可以使用老式的for..loop。
诀窍是从末端开始并向后循环

For x = NeededList.Count - 1 to 0 Step -1
    ' Get the element to evaluate....
    Dim Needed = NeededList(x)
    .....
    If dr.HasRows Then
        NeededList.RemoveAt(x)
    End If
Next
您需要以这种方式处理循环,因为您不会因为当前元素已被删除而有跳过元素的风险


例如,假设删除集合中的第四个元素,然后第五个元素成为第四个元素。但是索引器将上升到5。这样,前一个第五个元素(现在处于第四位置)从未计算过。当然,您可以尝试更改索引器的值,但最终总是会出现错误代码和等待发生的bug。

请确保安全,并使用
ToList()创建副本。


不,您不能从正在处理的列表中删除,例如。 对于ListOfstring中的每个Str作为字符串 如果Str.Equals(“Pat”),则 Dim index=listOfStrings.IndexOf(Str) listOfStrings.RemoveAt(索引) 如果结束 下一个

但是这种方法可以复制你的列表并从中删除。 对于ListOfstring中的每个Str作为字符串 如果Str.Equals(“Pat”),则 Dim index=ListofStringScope.IndexOf(Str) StringScope.RemoveAt列表(索引) 如果结束
接下来

您还可以反转列表元素的顺序,并使用
IEnumerable Cast
Reverse
扩展对每个使用

使用列表(字符串)的简单示例:

这个怎么样(不需要迭代):


如何使用此方法拆分每个项目?如何使用此方法拆分每个项目?答案已更新。您可以毫无问题地从需求列表中删除,因为使用不同的For循环可以从其中的最后一个元素开始。我收到此错误
“x”未声明。由于其保护级别,它可能无法访问。
如何使用此方法拆分每个项目?您可以像在原始代码中那样拆分
所需的
变量。当我尝试时,它会说,
所需的
尚未声明,因为我在这行代码中为每个所需的
声明了它在我已经替换的NeededList中。
Dim Needed=NeededList(x)
,正如Steve在代码的第二行中所做的。明白了。抱歉,太密集了!这是一个很好的简单解决方案,不需要反向迭代,如果你想按FIFO顺序处理,这是不方便的。我知道有很多不同的方法来解决这个问题“剥猫皮”但是这个对我很有效。我已经花了好几个小时删除了每个
循环,直到我最终找到了你的
.ToList
。谢谢分享!
For Each Needed In NeededList.ToList()
    Dim Ticker = Needed.Split("-")(0).Trim()
    ...
    If dr.HasRows Then
        NeededList.Remove(Needed)
    End If
Next
For Each Needed In NeededList.Cast(Of List(Of String)).Reverse()
    If dr.HasRows Then
        NeededList.Remove(Needed)
    End If
Next
NeededList = (NeededList.Where(Function(Needed) IsNeeded(Needed)).ToList

Function IsNeeded(Needed As ...) As Boolean
    ...
    Return Not dr.HasRows
End Function