2010-06-04 109 views
0

我正在編寫一個應用程序,用於將listbox1上的每個項目與listbox2上的所有項目進行比較。如果找到該項目,則將其從兩個列表中刪除。我們的目標是隻讓那些未找到的項目保留在這兩個列表中。VB.NET 2008應用程序在執行循環期間崩潰

問題是,應用程序只是掛起,我從來沒有得到任何結果。我多次查看我的代碼,我無法弄清楚發生了什麼事(編程noob我知道...)。

有人可以幫我嗎?

代碼段:

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 
+0

如果任何一個列表框在列表框中有模糊怎麼辦? LB1 = ABCA,LB2 = zBCDEFz。結果應該是什麼?見測試代碼。 – dbasnett 2010-06-05 12:14:33

回答

1

如果ListBox1.Items.Count更是ListBox2.Items.Count - 1,X絕不等於ListBox1.Items.Count,所以使用Exit Do將永遠運行,代碼只會無限循環的

Do While y = 1 

你有沒有考慮使用LINQ例如,爲了便於列表管理?

編輯:此外,從列表中刪除您正在遍歷的項目(這對於For Each來說完全是非法的)是錯誤的,因爲每次刪除都會偏移循環計數器。

EDIT2:下面是完成任務的一個LINQ片段:

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 

是什麼呢基本上是提取兩個列表中的字符串(因爲ListBox.Items集合是一個有點古怪,這是必要的)

之後,我們運行交集方法並將結果複製到列表中。 (.ToList部分) 複製是一個必需的部分,否則愚蠢只會是ListBox的Items的一個子集,我們再次試圖通過拉動我們的鞋帶來提升自己。

最後一部分只是一個簡單的刪除循環,即從集合中刪除的項目

+0

我瀏覽過,並遇到此頁http://msdn.microsoft.com/en-us/netframework/aa904594.aspx LINQ是一個可下載的加載項? – 2010-06-04 20:26:34

+0

不是,它更像是一種簡化數據管理的語言功能。它可以從VS2008向上 – SWeko 2010-06-04 20:37:22

+0

添加了一個基於LINQ的解決方案,基本上是Joel Coehoorn解決方案的修改和解釋版本 – SWeko 2010-06-04 20:51:59

2

你有

ElseIf x = ListBox1.Items.Count Then 
    Exit Do 

當它應該是

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

,因爲你的循環將更改X進行計數,然後退出而不重複該值。

不僅如此,但爲什麼有一個Do循環呢?有沒有必要繼續迭代相同的內部列表框尋找重複,是嗎?

第三,你不應該刪除的東西,而你通過它們迭代。在你的情況下,for循環正在重用count,所以它是「安全的」,但remove操作將重新索引事物,所以當你刪除時,你應該從你的i和x迭代器中減1,這樣下一個就不會被重新索引。

再次想到,也許你把那個Do循環放在那裏,以覆蓋前一次跳過的元素,正如我的第三點所述。

+0

我試過了,但問題仍然存在。我明白你的意思是x計數的變化。是的,我把Do循環放在那裏,所以它實際上每次都覆蓋整個索引(性能沒什麼問題,列表只有2500行。) – 2010-06-04 20:28:03

1

如果您使用Visual Studio 2008或更高版本:

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 
+0

不幸的是我只能訪問Visual Basic 2008 Express版,所以我想這就是爲什麼我看不到這個功能。 – 2010-06-04 20:25:51

+0

@RedHaze應該處理這個很好。儘管如此,您還是需要一個Imports System.Linq。 – 2010-06-04 20:27:54

+0

謝謝你的耐心等待!我在頂部添加了導入,但仍然收到:'Intersect'不是System.Windows.Forms.ListBox.ObjectCollection' – 2010-06-04 20:29:54

0

我跑了三種不同的方法進行測試。他們是喬爾斯,斯科和我的。我正在做這個測試性能,但是我發現結果不一樣,的列表框不一樣。這是我用來測試的代碼,所以你可以成爲裁判。可能是我的一些愚蠢的錯誤。

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 

此外,正如所料,LINQ更簡潔但更慢。如果代碼很少使用,則無關緊要。我對LINQ和Eratosthenes篩選有過不好的經驗。

+0

我認爲我的速度會比較慢,因爲我猜的是Cast的調用類型()。至於linq,如果使用正確,它可以非常快,但你必須小心。任何時候你發現自己調用.ToList()或.ToArray()都會導致性能下降。在這種情況下,有必要避免潛在的競爭條件。 – 2010-06-05 14:09:32

+0

@Joel Coehoorn - 結果有什麼不同?這只是我,但我從來沒有見過LINQ在這種事情上更快的情況。 – dbasnett 2010-06-05 14:13:34

+0

你是對的。該代碼將每月使用兩次,總數低於10,000條的設置數據。我用3000左右的記錄進行的測試花費了大約3秒鐘,這確實比他們使用的老方法(手動比較)要好。我並沒有期待你們有這麼多的幫助,反饋一直都很驚人。非常感謝你。 – 2010-06-06 14:53:46