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

Posted

技术标签:

【中文标题】使用 For Each 循环遍历列表时删除列表中的项目【英文标题】:Removing Items in a List While Iterating Through It with For Each Loop 【发布时间】:2013-10-15 15:31:01 【问题描述】:

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

【问题讨论】:

【参考方案1】:

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

【讨论】:

如何用这种方法拆分每个项目? 您可以像在原始代码中那样拆分Needed 变量。 当我尝试它说 Needed 没有被声明,因为我在这行代码 For Each Needed In NeededList 中声明了它,我已经替换了它。 Dim Needed = NeededList(x) 正如史蒂夫在第二行代码中所说的那样。 知道了。抱歉太密集了!【参考方案2】:

安全起见并使用ToList()复制:

For Each Needed In NeededList.ToList()
    Dim Ticker = Needed.Split("-")(0).Trim()
    ...
    If dr.HasRows Then
        NeededList.Remove(Needed)
    End If
Next

【讨论】:

这是一个很好的简单解决方案,不需要向后迭代,如果您想按 FIFO 顺序处理,这并不方便。我知道有很多不同的方法可以“给猫剥皮”,但这一种对我来说效果很好。 在我终于找到你的.ToList 之前,我删除了For Each 循环已经浪费了几个小时。感谢分享!【参考方案3】:

您可以使用 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

【讨论】:

如何用这种方法拆分每个项目? 答案已更新。您可以毫无问题地从 NeedList 中删除,因为使用不同的 For 循环是从其中的最后一个元素开始的。 我收到此错误"x" is not declared. It may be inaccessible due to its protection level.【参考方案4】:

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

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

【讨论】:

如何用这种方法拆分每个项目?【参考方案5】:

不,您不能从您正在处理的列表中删除,例如 对于 listOfStrings 中的每个 Str 作为字符串 If Str.Equals("Pat") Then 暗淡索引 = listOfStrings.IndexOf(Str) listOfStrings .RemoveAt(index) 万一 下一个

但是这种方式可以复制您的列表并从中删除,例如 对于 listOfStrings 中的每个 Str 作为字符串 If Str.Equals("Pat") Then 暗淡索引 = listOfStringsCopy.IndexOf(Str) listOfStringsCopy.RemoveAt(索引) 万一 下一个

【讨论】:

【参考方案6】:

您还可以通过 IEnumerable CastReverse 扩展名来反转列表元素的顺序并仍然使用 For Each

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

For Each Needed In NeededList.Cast(Of List(Of String)).Reverse()
    If dr.HasRows Then
        NeededList.Remove(Needed)
    End If
Next

【讨论】:

【参考方案7】:

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

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

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

【讨论】:

以上是关于使用 For Each 循环遍历列表时删除列表中的项目的主要内容,如果未能解决你的问题,请参考以下文章

循环遍历 SCSS 中的两个 @each 列表

Python3基础 使用for循环 删除一个列表中的重复项

为啥 for 循环不遍历列表中的每个项目?

Python列表list操作-遍历查找增加删除修改排序

如何在 Zoho CRM Deluge 脚本中使用 for each 循环遍历 JSON 数组

For Each 循环:循环通过 Outlook 邮箱删除项目时,某些项目会被跳过