17

我有一个名为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
4

7 回答 7

37

不,你不能使用 for each 来做到这一点,但你可以使用老式的 for .. 循环来做到这一点。
诀窍是从头开始并向后循环。

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。这样,前一个第五个元素(现在在第四个位置)永远不会被评估。当然,您可以尝试更改索引器的值,但这总是以错误的代码和等待发生的错误告终。

于 2013-10-08T15:47:30.787 回答
17

确保安全并使用以下命令制作副本ToList()

For Each Needed In NeededList.ToList()
    Dim Ticker = Needed.Split("-")(0).Trim()
    ...
    If dr.HasRows Then
        NeededList.Remove(Needed)
    End If
Next
于 2013-10-09T09:40:12.897 回答
4

您可以使用 For 循环通过 Step -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
于 2013-10-08T15:46:27.813 回答
3

数组的内容(或任何其他可以快速枚举的内容For Each都不能用循环修改For Each。您需要使用简单的For循环并遍历每个索引。

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

于 2013-10-08T15:45:15.310 回答
0

不,您不能从您正在处理的列表中删除例如 For Each Str As String In listOfStrings If Str.Equals("Pat") Then Dim index = listOfStrings.IndexOf(Str) listOfStrings .RemoveAt(index) End If Next

但是这种方式可以复制您的列表并从中删除,例如 For Each Str As String In listOfStrings If Str.Equals("Pat") Then Dim index = listOfStringsCopy.IndexOf(Str) listOfStringsCopy.RemoveAt(index) End If下一个

于 2015-04-17T11:51:37.033 回答
0

您还可以反转列表元素的顺序,并且仍然使用For EachandIEnumerable Cast扩展Reverse名。

使用 List(Of String) 的简单示例:

For Each Needed In NeededList.Cast(Of List(Of String)).Reverse()
    If dr.HasRows Then
        NeededList.Remove(Needed)
    End If
Next
于 2016-05-26T02:55:53.993 回答
0

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

NeededList = (NeededList.Where(Function(Needed) IsNeeded(Needed)).ToList

Function IsNeeded(Needed As ...) As Boolean
    ...
    Return Not dr.HasRows
End Function
于 2016-09-20T00:08:12.143 回答