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
Était-ce utile?

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top