我正在编写一个应用程序来将listbox1上的每个项目与listbox2上的所有项目进行比较。如果找到该项,则将其从两个列表中删除。目标是只在两个列表中保留未找到的项目。
问题是,应用程序只是挂起而且我从来没有得到任何结果。我几次看了我的代码,我无法弄清楚发生了什么(我知道编程菜鸟......)。
有人可以帮我吗?
代码段:
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 :(得分:2)
你有
ElseIf x = ListBox1.Items.Count Then
Exit Do
什么时候应该
ElseIf x = ListBox1.Items.Count - 1 Then
Exit Do
因为你的for循环会将X改为count,然后退出而不迭代该值。
不仅如此,为什么还有Do
循环呢?没有必要继续迭代相同的内部列表框来寻找重复项,是吗?
第三,你不应该在迭代它们时删除它们。在你的情况下,for循环是重用count,所以它是“安全的”但是remove操作会重新索引东西,所以当你删除时你应该从你的i和x迭代器中减去1,这样重建索引就不会跳过下一个循环
第二个想法,也许你把Do
循环放在那里以覆盖前一次跳过的元素,如我的第三点所述。
答案 1 :(得分:1)
如果ListBox1.Items.Count多于ListBox2.Items.Count - 1,则X将永远不会等于ListBox1.Items.Count,因此Exit Do将永远不会运行,并且代码将在
Do While y = 1
您是否考虑过使用Linq,以便更轻松地进行列表管理?
编辑:此外,从使用for进行遍历的列表中删除项目是错误的(使用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集合有点奇怪)
之后我们运行intersect方法并将结果复制到列表中。 (.ToList部分) 复制是必需的部分,因为否则dupes只是ListBox项目的一个子集,我们将再一次尝试通过拉动我们的鞋带来提升自己。
最后一部分只是一个简单的删除循环,它从集合中删除了项目
答案 2 :(得分: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
答案 3 :(得分:0)
我对三种不同方法进行了测试。他们是Joels,sweko和我的。我这样做是为了测试性能,但我发现结果不一样,列表框不一样。这是我用来测试的代码,所以你可以做出判断。我可能有些愚蠢的错误。
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的Sieve有不好的经验。