【问题标题】:Removing Items in a List While Iterating Through It with For Each Loop使用 For Each 循环遍历列表时删除列表中的项目
【发布时间】: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

【问题讨论】:

    标签: vb.net list loops foreach


    【解决方案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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-09-07
          • 2011-01-04
          • 1970-01-01
          • 1970-01-01
          • 2017-02-08
          • 2021-05-25
          • 1970-01-01
          • 2022-01-06
          相关资源
          最近更新 更多