VB.NET 2008 Application plantage lors de boucle Do
Question
Je suis en train d'écrire une application pour comparer chaque élément listbox1 à tous les articles sur ListBox2. Si l'élément est trouvé, puis retirez-les deux listes. L'objectif est d'avoir uniquement les éléments qui ne sont pas trouvés restent sur les deux listes.
Le problème est, l'application juste et se bloque je ne me donnent aucun résultat. Je regardais mon code plusieurs fois et je ne peux pas comprendre ce qui se passe (programmation Noob je sais ...).
aide quelqu'un peut me avec cela?
Code Snippet:
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim a As String
Dim b As String
Dim y As String
For i As Integer = 0 To ListBox1.Items.Count - 1
a = ListBox1.Items(i)
y = 1
Do While y = 1
For x As Integer = 0 To ListBox2.Items.Count - 1
b = ListBox2.Items(x)
Dim res As Int16 = String.Compare(a, b)
If res = 0 Then
y = 0
ListBox2.Items.Remove(i)
ListBox2.Items.Remove(x)
ElseIf x = ListBox1.Items.Count Then
Exit Do
End If
Next
Loop
Next
End Sub
La solution
si ListBox1.Items.Count est plus que ListBox2.Items.Count - 1, X ne sera jamais égale ListBox1.Items.Count, de sorte que la sortie Do ne sera jamais exécuté, et le code sera juste boucle sans fin dans le
Do While y = 1
Avez-vous pensé à utiliser LINQ par exemple, pour la gestion des listes plus facile?
modifier. De plus, il est faux de supprimer un élément de la liste que vous avec un déplacement pour (il est carrément illégal de le faire avec un pour chaque) parce que chaque suppression compensera le compteur de boucle
Edit2: voici un extrait de code Linq qui accomplit la tâche:
Dim itemsFirst = (From item As String In ListBox1.Items Select item)
Dim itemsSecond = (From item As String In ListBox2.Items Select item)
Dim dupes = System.Linq.Enumerable.Intersect(itemsFirst, itemsSecond).ToList
For Each item In dupes
ListBox1.Items.Remove(item)
ListBox2.Items.Remove(item)
Next item
ce qui est fait est d'extraire essentiellement les chaînes à la fois la liste (ce qui est nécessaire parce que la collection ListBox.Items est un peu bizarre)
Après que nous courons la méthode Intersection et copier les résultats dans une liste. (La partie .ToList) La copie est une partie nécessaire parce que, sinon dupes serait juste un sous-ensemble des éléments de la ListBox, et encore une fois nous serions essayer de nous soulever en tirant sur nos shoestrings.
La dernière partie est une simple boucle de suppression, qui supprime les éléments de la collection
Autres conseils
vous avez
ElseIf x = ListBox1.Items.Count Then
Exit Do
quand il doit être
ElseIf x = ListBox1.Items.Count - 1 Then
Exit Do
parce que votre boucle va changer X compter, puis sortir sans itérer à cette valeur.
Non seulement cela, mais pourquoi est-il une boucle de Do
de toute façon? Il n'y a pas besoin de garder itérer la même zone de liste intérieure à la recherche de doublons, est-il?
Troisièmement, vous ne devriez pas enlever des choses pendant que vous itérer à travers eux. Dans votre cas, pour les boucles réutilisent le nombre, il est donc « sûr », mais l'opération de suppression réindexera choses, vous devez soustraire 1 de votre i et x itérateurs lorsque vous supprimez, de sorte que le prochain ne soit pas sauté par la réindexation .
À la réflexion, peut-être que vous mettez cette boucle de Do
là pour couvrir les éléments sautée la dernière fois autour, comme mentionné dans mon troisième point.
Si vous utilisez Visual Studio 2008 ou plus tard:
Dim dupes = Listbox1.Items.Cast(Of String)().Intersect(Listbox2.Items.Cast(Of String)()).ToArray()
For Each item As String in dupes
Listbox1.Items.Remove(item)
Listbox2.Items.Remove(item)
Next item
J'ai couru un test de trois méthodes différentes. Ils sont Joels, sweko, et le mien. Je faisais cela à la performance de test, mais je trouve les résultats ne sont pas les mêmes, les listboxes ne sont pas les mêmes . Voici le code que j'utilisé pour tester, vous pouvez être le juge. Probablement une erreur stupide de ma part.
Dim stpw As New Stopwatch
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Debug.WriteLine("")
loadLBTD() ''#load test data
doSTPW("Test 1 Start", False) ''#mine
''#get rid of dupes <<<<<<<<<<<<<<
Dim dupeL As New List(Of String)
For x As Integer = ListBox1.Items.Count - 1 To 0 Step -1
If ListBox2.Items.Contains(ListBox1.Items(x)) Then
dupeL.Add(ListBox1.Items(x))
ListBox1.Items.RemoveAt(x)
End If
Next
For Each s As String In dupeL
ListBox2.Items.Remove(s)
Next
doSTPW("Test 1 End")
loadLBTD() ''#load test data
doSTPW("Test 2 Start", False) ''#sweko
''#get rid of dupes <<<<<<<<<<<<<<
''#I had to set Option Strict to Off to get this to work <<<<<<<
Dim itemsFirst = (From item As String In ListBox1.Items Select item)
Dim itemsSecond = (From item As String In ListBox2.Items Select item)
Dim dupes = System.Linq.Enumerable.Intersect(itemsFirst, itemsSecond).ToList
For Each item In dupes
ListBox1.Items.Remove(item)
ListBox2.Items.Remove(item)
Next item
doSTPW("Test 2 End")
loadLBTD() ''#load test data
doSTPW("Test 3 Start", False) ''#joel
''#get rid of dupes <<<<<<<<<<<<<<
Dim dupes2 = ListBox1.Items.Cast(Of String)().Intersect(ListBox2.Items.Cast(Of String)()).ToArray()
For Each item As String In dupes2
ListBox1.Items.Remove(item)
ListBox2.Items.Remove(item)
Next item
doSTPW("Test 3 End")
End Sub
Private Sub doSTPW(ByVal someText As String, Optional ByVal showTM As Boolean = True)
stpw.Stop() ''#stop the clock
If flip Then Debug.Write("'T ") Else Debug.Write("'F ")
Debug.Write("LBCnts " & ListBox1.Items.Count & " " & ListBox2.Items.Count)
Dim s As String
If showTM Then
s = String.Format(" {0} {1}", someText, stpw.ElapsedTicks.ToString("N0"))
Else
s = String.Format(" {0}", someText)
End If
Debug.WriteLine(s)
stpw.Reset() ''#reset and start clock
stpw.Start()
End Sub
Dim flip As Boolean = False
Private Sub loadLBTD()
''#Create test data
Dim tl1() As String = New String() {"A", "X", "y", "z", "B", "w", "X", "y", "z"}
Dim tl2() As String = New String() {"A", "y", "z", "Q", "A", "y", "z", "Q", "A", "y", "z", "Q"}
ListBox1.Items.Clear()
ListBox2.Items.Clear()
''#load listboxes
If flip Then
ListBox1.Items.AddRange(tl2)
ListBox2.Items.AddRange(tl1)
Else
ListBox1.Items.AddRange(tl1)
ListBox2.Items.AddRange(tl2)
End If
''#end of test data setup
End Sub
En outre, comme prévu, LINQ est plus concis, mais plus lent. Si le code est rarement utilisé, il n'a pas d'importance. J'ai eu une mauvaise expérience avec LINQ et d'Eratosthène Sieve.