I have a list named NeededList
I need to check each item in this list to see if it exists in my database. If it does exist in the database I need to remove it from the list. But I can't change the list while I'm iterating through it. How can I make this work?
我有一个名为NeededList的列表我需要检查此列表中的每个项目,看它是否存在于我的数据库中。如果它确实存在于数据库中,我需要将其从列表中删除。但是当我迭代它时,我无法更改列表。我怎样才能做到这一点?
Here is my code so far:
这是我到目前为止的代码:
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
7 个解决方案
#1
29
No you can't do that using a for each, but you can do that using the old fashioned for .. loop.
The trick is to start from the end and looping backwards. In this way, while you remove elements from the list, you move towards the first element and you never skip elements because the current one has been deleted and your indexer is incremented.
不,你不能使用for each,但你可以使用旧式的for循环来做到这一点。诀窍是从结束开始并向后循环。通过这种方式,当您从列表中删除元素时,您将移向第一个元素,并且您永远不会跳过元素,因为当前的元素已被删除且您的索引器已递增。
For x = NeededList.Count - 1 to 0 Step -1
Dim Needed = NeededList(x)
.....
If dr.HasRows Then
NeededList.RemoveAt(x)
End If
Next
Instead, if you loop towards the end of the collection and decide to remove an element, you skip the next one. For example, suppose that you remove the fourth element in the collection, after that, the fifth element becomes the fourth. But now the indexer goes up to 5. In this way, the previous fifth element (now in fourth position) is never evaluated. Of course you could try to change the value of the indexer but this ends always in bad code and bugs waiting to happen.
相反,如果您循环到集合的末尾并决定删除元素,则跳过下一个元素。例如,假设您删除了集合中的第四个元素,之后,第五个元素成为第四个元素。但现在索引器上升到5.这样,前五个元素(现在处于第四位)永远不会被评估。当然,您可以尝试更改索引器的值,但这总是在错误的代码和等待发生的错误中结束。
#2
12
Go for safe and make a copy with ToList()
:
为安全起见并使用ToList()制作副本:
For Each Needed In NeededList.ToList()
Dim Ticker = Needed.Split("-")(0).Trim()
...
If dr.HasRows Then
NeededList.Remove(Needed)
End If
Next
#3
4
You can use a For loop iterating through every index with Step -1.
您可以使用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
#4
3
The contents of an array (or anything else you can fast enumerate with For Each
can not be modified with a For Each
loop. You need to use a simple For
loop and iterate through every index.
数组的内容(或者您可以使用For Each快速枚举的任何其他内容都无法使用For Each循环进行修改。您需要使用简单的For循环并遍历每个索引。
Hint: Because you'll be deleting indexes, I suggest starting at the last index and work your way toward the first index so you don't skip over one every time you delete one.
提示:因为你要删除索引,我建议从最后一个索引开始,然后按照第一个索引的方式进行操作,这样每次删除索引时都不会超过一个索引。
#5
0
No you can not remove from a List that you are working on e.g. 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 = listOfStrings.IndexOf(Str)listOfStrings .RemoveAt(index)End If Next
But this way will work make a copy of your list and delete from it e.g. For Each Str As String In listOfStrings If Str.Equals("Pat") Then Dim index = listOfStringsCopy.IndexOf(Str) listOfStringsCopy.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 Next
#6
0
You can also invert the order of the list's elements and still use For Each
using the IEnumerable Cast
and Reverse
extensions.
您还可以反转列表元素的顺序,并仍然使用IEnumerable Cast和Reverse扩展使用For Each。
Simple example using a List(Of String):
使用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
0
How about this (no iteration needed):
怎么样(不需要迭代):
NeededList = (NeededList.Where(Function(Needed) IsNeeded(Needed)).ToList
Function IsNeeded(Needed As ...) As Boolean
...
Return Not dr.HasRows
End Function
#1
29
No you can't do that using a for each, but you can do that using the old fashioned for .. loop.
The trick is to start from the end and looping backwards. In this way, while you remove elements from the list, you move towards the first element and you never skip elements because the current one has been deleted and your indexer is incremented.
不,你不能使用for each,但你可以使用旧式的for循环来做到这一点。诀窍是从结束开始并向后循环。通过这种方式,当您从列表中删除元素时,您将移向第一个元素,并且您永远不会跳过元素,因为当前的元素已被删除且您的索引器已递增。
For x = NeededList.Count - 1 to 0 Step -1
Dim Needed = NeededList(x)
.....
If dr.HasRows Then
NeededList.RemoveAt(x)
End If
Next
Instead, if you loop towards the end of the collection and decide to remove an element, you skip the next one. For example, suppose that you remove the fourth element in the collection, after that, the fifth element becomes the fourth. But now the indexer goes up to 5. In this way, the previous fifth element (now in fourth position) is never evaluated. Of course you could try to change the value of the indexer but this ends always in bad code and bugs waiting to happen.
相反,如果您循环到集合的末尾并决定删除元素,则跳过下一个元素。例如,假设您删除了集合中的第四个元素,之后,第五个元素成为第四个元素。但现在索引器上升到5.这样,前五个元素(现在处于第四位)永远不会被评估。当然,您可以尝试更改索引器的值,但这总是在错误的代码和等待发生的错误中结束。
#2
12
Go for safe and make a copy with ToList()
:
为安全起见并使用ToList()制作副本:
For Each Needed In NeededList.ToList()
Dim Ticker = Needed.Split("-")(0).Trim()
...
If dr.HasRows Then
NeededList.Remove(Needed)
End If
Next
#3
4
You can use a For loop iterating through every index with Step -1.
您可以使用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
#4
3
The contents of an array (or anything else you can fast enumerate with For Each
can not be modified with a For Each
loop. You need to use a simple For
loop and iterate through every index.
数组的内容(或者您可以使用For Each快速枚举的任何其他内容都无法使用For Each循环进行修改。您需要使用简单的For循环并遍历每个索引。
Hint: Because you'll be deleting indexes, I suggest starting at the last index and work your way toward the first index so you don't skip over one every time you delete one.
提示:因为你要删除索引,我建议从最后一个索引开始,然后按照第一个索引的方式进行操作,这样每次删除索引时都不会超过一个索引。
#5
0
No you can not remove from a List that you are working on e.g. 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 = listOfStrings.IndexOf(Str)listOfStrings .RemoveAt(index)End If Next
But this way will work make a copy of your list and delete from it e.g. For Each Str As String In listOfStrings If Str.Equals("Pat") Then Dim index = listOfStringsCopy.IndexOf(Str) listOfStringsCopy.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 Next
#6
0
You can also invert the order of the list's elements and still use For Each
using the IEnumerable Cast
and Reverse
extensions.
您还可以反转列表元素的顺序,并仍然使用IEnumerable Cast和Reverse扩展使用For Each。
Simple example using a List(Of String):
使用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
0
How about this (no iteration needed):
怎么样(不需要迭代):
NeededList = (NeededList.Where(Function(Needed) IsNeeded(Needed)).ToList
Function IsNeeded(Needed As ...) As Boolean
...
Return Not dr.HasRows
End Function