Domanda

vi scrivo un'applicazione per confrontare ciascun elemento ListBox1 a tutti gli elementi su ListBox2. Se l'articolo è trovato, quindi elimina da entrambe le liste. L'obiettivo è quello di avere solo gli elementi che non sono stati trovati rimangono in entrambe le liste.

Il problema è, l'applicazione si blocca solo e non ho mai ottenere alcun risultato. Ho guardato il mio codice più volte e non riesco a capire cosa sta succedendo (programmazione niubbo lo so ...).

Qualcuno può aiutarmi a questo?

Snippet di codice:

    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
È stato utile?

Soluzione

se ListBox1.Items.Count è più che ListBox2.Items.Count - 1, X non sarà mai uguale ListBox1.Items.Count, quindi l'uscita Do non potrà mai funzionare, e il codice sarà solo ciclo senza fine nel

Do While y = 1

Hai pensato di usare LINQ per esempio, per la gestione delle liste più facile?

modifica:. Inoltre è sbagliato eliminare un elemento dalla lista che si sta movimento con una per (è addirittura illegale di farlo con un For Each) perché ogni eliminazione compenserà il contatore del ciclo

EDIT2: Ecco un frammento di Linq che compie l'operazione:

    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

ciò che è non è fondamentalmente estrarre le stringhe di entrambe lista (questo è necessario perché la collezione ListBox.Items è un po 'strano)

Dopo che corriamo il metodo Intersect e copiare i risultati in una lista. (La parte ToList) La copia è una parte necessaria perché, altrimenti gonzi sarebbe solo un sottoinsieme degli elementi della ListBox, e ancora una volta ci sarebbe cercare di tirarsene tirando nostri shoestrings.

L'ultima parte è solo un semplice ciclo di eliminazione, che rimuove gli elementi della collezione

Altri suggerimenti

si deve

ElseIf x = ListBox1.Items.Count Then
    Exit Do

quando dovrebbe essere

ElseIf x = ListBox1.Items.Count - 1 Then
    Exit Do

perché il ciclo for cambierà X a contare, e poi uscire senza l'iterazione a quel valore.

Non solo, ma perché c'è un ciclo Do comunque? Non c'è alcuna necessità di mantenere l'iterazione stessa casella di riepilogo interno alla ricerca di duplicati, è?

E in terzo luogo, non si deve rimuovere le cose mentre si scorre attraverso di loro. Nel tuo caso la cicli for sono il riutilizzo di conteggio, quindi è "sicuro", ma l'operazione di rimozione sarà reindex cose, così si dovrebbe sottrarre 1 dal ie x iteratori quando si rimuove, in modo che il prossimo non è saltato dalla reindicizzazione .

Il secondo pensiero, forse si mette quel ciclo Do lì per coprire gli elementi saltato la volta precedente in giro, come accennato nel mio terzo punto.

Se stai usando Visual Studio 2008 o successivamente:

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

I correva una prova di tre diversi metodi. Sono Joels, SWEKO, e la mia. Stavo facendo questo per le prestazioni del test, ma ho scoperto che i risultati non sono gli stessi, le listboxes non sono gli stessi . Ecco il codice che ho usato per testare, in modo da poter essere il giudice. Probabilmente qualche errore stupido da parte mia.

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

Inoltre, come previsto, LINQ è più conciso ma più lento. Se il codice viene utilizzato di rado non ha importanza. Ho avuto una brutta esperienza con LINQ e Crivello di Eratostene.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top