web-dev-qa-db-fra.com

Suppression d'éléments dans une liste lors d'une itération avec pour chaque boucle

J'ai une liste nommée NeededList Je dois vérifier chaque élément de cette liste pour voir s'il existe dans ma base de données. S'il existe dans la base de données, je dois le supprimer de la liste. Mais je ne peux pas changer la liste pendant que je parcours à travers elle. Comment puis-je faire ce travail?

Voici mon code jusqu'à présent:

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
12
gromit1

Non, vous ne pouvez pas faire cela en utilisant un pour chacun, mais vous pouvez le faire en utilisant la boucle à l'ancienne.
L'astuce consiste à partir de la fin et à boucler en arrière. 

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

Vous devez aborder la boucle de cette manière car vous ne risquez pas de sauter des éléments car celui en cours a été supprimé.

Par exemple, supposons que vous supprimiez le quatrième élément de la collection, puis que le cinquième devienne le quatrième. Mais alors l'indexeur monte à 5. De cette manière, le cinquième élément précédent (maintenant en quatrième position) n'est jamais évalué. Bien sûr, vous pouvez essayer de changer la valeur de l'indexeur mais cela finit toujours par un code incorrect et des bugs en attente.

31
Steve

Optez pour le coffre-fort et faites une copie avec ToList():

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

Vous pouvez utiliser une boucle For pour parcourir chaque index à l’étape -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
tezzo

Le contenu d'un tableau (ou de tout ce que vous pouvez énumérer rapidement avec For Each ne peut pas être modifié avec une boucle For Each. Vous devez utiliser une simple boucle For et parcourir tous les index.

Conseil: comme vous allez supprimer des index, je vous suggère de commencer par le dernier index et de vous diriger vers le premier index afin de ne pas en sauter un à chaque fois que vous en supprimez un.

3
nhgrif

Vous pouvez également inverser l'ordre des éléments de la liste et continuer à utiliser For Each en utilisant les extensions IEnumerable Cast et Reverse.

Exemple simple utilisant une liste (de chaîne):

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

Que diriez-vous de cela (pas d'itération nécessaire):

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

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

Non, vous ne pouvez pas supprimer d'une liste sur laquelle vous travaillez, par exemple . For Each Str As String dans listOfStrings Si Str.Equals ("Pat") Alors Dim index = listOfStrings.IndexOf (Str) listOfStrings .RemoveAt (index) Fin si Suivant

Mais cette méthode fonctionnera pour faire une copie de votre liste et la supprimer, par exemple . Pour chaque Str As String dans listOfStrings .__ Si Str.Equals ("Pat") Alors Dim index = listOfStringsCopy.IndexOf (Str) listOfStringsCopy.RemoveAt (index) Fin si Suivant

0
Pec1983