使用 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 Cast
和 Reverse
扩展名来反转列表元素的顺序并仍然使用 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 循环遍历列表时删除列表中的项目的主要内容,如果未能解决你的问题,请参考以下文章