VB.Net - Remove empty items in ListBox - vb.net

I want to remove empty items from my listbox that looks something like this:
book1
book2
book3
book4
book5
And so on..
I have tried this code:
Dim i As Integer = 0
Do While (ListBox1.Items.Count) - 1 >= i
If String.IsNullOrEmpty(ListBox1.Items(i)) Then
ListBox1.Items.Remove(ListBox1.Items(i))
i -= 1
End If
i += 1
Loop
And i don't know why it's not working.

You can use any type of loop for any purpose but each type is best suited to certain situations and a Do While loop is a poor choice in this case. The best option in this case is to use a For loop and count backwards:
For i = ListBox1.Items.Count - 1 To 0 Step -1
If String.IsNullOrEmpty(CStr(ListBox1.Items(i))) Then
ListBox1.Items.RemoveAt(i)
End If
Next

Related

Even Odd numbers using Nested For Next Loop VBA

How do I create a For-Next loop determining whether the numbers listed are even or odd
You can try something like this:
Dim i As Integer
For i = 1 To 6
If i mod 2 = 0 Then
'i is even
Else
'i is odd
End If
Next i

Remove elements in an arraylist that exist in another arraylist

i have 2 array list, dateListDead and dateListNotMinggu. Both is DateTime List of Array. This is the ilustration of the date value in list of array
The arrayList value
its supposed to remove specific element that exist in other array list.
so far i tried, this code it's not working.
Dim d, x As Integer
For x = 0 To dateListDead.Count - 1
For d = 0 To dateListNotMinggu.Count - 1
If dateListNotMinggu(d) = dateListDead(x) Then
dateListNotMinggu.RemoveAt(d)
End If
Next
Next
the error is : index out of range. how could it be ? i define the parameter of end looping base on arraylist.count -1
The main is that you are using a For loop from the first index to the last index but you don't account for the change of index when you remove a value. If there might be multiple values then you should start and the end rather than the beginning. In that case, removing an item won't affect the indexes of the items you are yet to test. If there can only be one match then you should be exiting the loop when you find one.
Either way, while you don't have to, I would suggest using a For Each loop on the outside. If you want to perform an action for each item in a list then that's exactly what a For Each loop is for. Only use a For loop if you need to use the loop counter for something other than accessing each item in turn.
For multiple matches:
For Each dateDead As Date In dateListDead
For i = dateListNotMinggu.Count - 1 To 0 Step -1
If CDate(dateListNotMinggu(i)) = dateDead Then
dateListNotMinggu.RemoveAt(i)
End If
Next
Next
For a single match:
For Each dateDead As Date In dateListDead
For i = 0 To dateListNotMinggu.Count - 1
If CDate(dateListNotMinggu(i)) = dateDead Then
dateListNotMinggu.RemoveAt(i)
Exit For
End If
Next
Next
Note that I have also cast the Date values as that type for comparison, which is required with Option Strict On. Option Strict is Off by default but you should always turn it On because it will help you write better code by focusing on data types.
Also, the code above would work with a List(Of Date) as well as an ArrayList but the casts would not be required with a List(Of Date). That's one of the advantages of using a generic List(Of T) over an ArrayList, which paces no restrictions on what it can contain.
If you really must use a For loop because that's what your homework assignment says then it would look like this:
For i = 0 To dateListDead.Count - 1
For j = dateListNotMinggu.Count - 1 To 0 Step -1
If CDate(dateListNotMinggu(j)) = CDate(dateListDead(i)) Then
dateListNotMinggu.RemoveAt(j)
End If
Next
Next
and this:
For i = 0 To dateListDead.Count - 1
For j = 0 To dateListNotMinggu.Count - 1
If CDate(dateListNotMinggu(j)) = CDate(dateListDead(i)) Then
dateListNotMinggu.RemoveAt(j)
Exit For
End If
Next
Next
Note that it is convention to use i as a first option for a loop counter, then j for the first nested loop, then k for the second nested loop. You should only use something else if you have good reason to do so. Remember that the loop counter doesn't represent the value in the list but rather its index. That's why you use i for index and not d for date or the like.
EDIT:
As per Jimi's comment below, the way this would usually be tackled is with a simple LINQ query. If you were using LINQ then you definitely wouldn't be using an ArrayList but rather a List(Of Date). In that case, the code would look like this:
dateListNotMinggu = dateListNotMinggu.Except(dateListDead).ToList()
If you were completely insane and wanted to use LINQ and ArrayLists then this would work:
dateListNotMinggu = New ArrayList(dateListNotMinggu.Cast(Of Date)().
Except(dateListDead.Cast(Of Date)()).
ToArray())
Take note that, as I replied in the comments, using LINQ will generate a new list, rather than changing the existing one.

InvalidArgument=Value of ' ' is not valid for 'index' (' ' inside number)

This is my first question. I can't solve this error for 2 weeks.
In order to solve the problem signed up.
This is my vb code.
Try
For i As Integer = 0 To ListBox1.Items.Count - 1 Step 1
For j As Integer = 0 To ListBox2.Items.Count - 1 Step 1
If ListBox1.Items(i).ToString().Equals(ListBox2.Items(j).ToString()) = True Then
ListBox1.Items.RemoveAt(i)
End If
Next
Next
Catch ex As Exception
MsgBox("LOAD ERROR: " + ex.Message, vbCritical, "ERROR")
End Try
error :
InvalidArgument=Value of '20' is not valid for 'index'(' ' is varient.)
Project has no problems except for this error
Try this:
Dim items = ListBox1.Items.Where(Function(item) ListBox2.Items.Contains(item)).ToList()
For Each item in items
ListBox1.Remove(item)
Next
When I run your code, I receive a different exception, argument out of range...and that is caused by deleting items from an indexed collection while you're iterating through it. For example, let's say listbox1 has 10 items in it. If you find item number 1 in listbox2 and delete it, now you only have 9 items left in listbox1. The problem is, when you entered your loop, you told it to loop 10 items, and it will still try to do that. At some point, if any items are deleted, this loop will throw an exception...so you will need to change that sooner or later. To mitigate this, step through the collection that you'll be deleting items from backward like this:
For i As Integer = ListBox1.Items.Count - 1 to 0 Step -1
When I run the code with the change shown above, it works as intended and removes the duplicate items from listbox1. Unfortunately, I was unable to reproduce your invalid argument exception. It's odd to see that because usually that exception likes to pop up when using listviews, not listboxes. Perhaps you can edit your post and add a screenshot of the data in your listboxes so it's easier for other people to troubleshoot.
As you remove items from ListBox1 the total item count will decrease (obviously), however the For loop does not respect that. A For loop will only have the right side of To set once, which is done prior to the first iteration.
What you're currently doing is actually equal to this:
Dim a As Integer = ListBox1.Items.Count - 1
For i As Integer = 0 To a Step 1
Dim b As Integer = ListBox2.Items.Count - 1
For j As Integer = 0 To b Step 1
...
Next
Next
The fix for this is simple; create a variable that holds how many items you have removed, then, in an If-statement, check if i is more or equal to the current item count subtracted with how many item's you've removed. If so, exit the loop.
Dim ItemsRemoved As Integer = 0
For i As Integer = 0 To ListBox1.Items.Count - 1 Step 1
If i >= ListBox1.Items.Count - ItemsRemoved Then Exit For
For j As Integer = 0 To ListBox2.Items.Count - 1 Step 1
If ListBox1.Items(i).ToString().Equals(ListBox2.Items(j).ToString()) = True Then
ListBox1.Items.RemoveAt(i)
End If
Next
Next
For future reference you should also always remove/comment out the Try/Catch-statement so you can see where the error occurs and get more detail about it.
The point of my answer is that when you iterating any collection, you should NOT try to modify this collection. In for-loops you run into such trouble. But you can iterate using while-loop with no issues
Try
Dim index As Integer = 0
While index < ListBox1.Items.Count '!! this code based on fact that ListBox1 item Count changes
For j As Integer = 0 To ListBox2.Items.Count - 1 ' <- this is ok because ListBox2 doesn't chage
If string.Equals(ListBox1.Items(index).ToString(), ListBox2.Items(j).ToString()) Then
ListBox1.Items.RemoveAt(index)
Continue While ' no index increase here because if you remove item N, next item become item N
End If
Next
index += 1
End While
Catch ex As Exception
MsgBox("LOAD ERROR: " + ex.Message, vbCritical, "ERROR")
End Try
This is good example of how things actually work. And it shows few techniques
I just selected Build-->Clean solution and it cleaned out the bad elements. This occurred as a result of adding and deleting menu items, without deleting the subroutines of the deleted menu items. As soon as I cleaned the solution, and then ran the project, the error was gone.

Removing rows from a Dictionary based on the next or last row

This is an offshoot of this question. Consider data thus:
1/1/2000 10000
1/1/2001 10000
1/1/2002 10000
10/1/2003 11000
1/1/2004 11000
1/1/2005 11000
6/1/2006 10000
9/1/2006 12000
This data is being collected into a SortedDictionary with the dates as the keys. I would like to convert it into this format:
1/1/2000 10000
10/1/2003 11000
6/1/2006 10000
9/1/2006 12000
That is, I want the earliest dated item for any given unique value. Normally when I'm presented with this sort of problem, I would iterate backwards...
for i = items.count - 1 to 1 step -1
if item(i) is like item(i-1) remove item(i)
next
But how do you do that with a SortedDictionary? Linq provides a reverse enumerator, and an index-ish thing, but Linq is only available on Windows. Is there an easy way to do this within basic VB.net I am unfamiliar with?
I solved this by making a List(Of Date), iterating backwards over that, then removing entries from the List. Then I iterate over the result and remove any key from the SortedDictionary. But that's seriously ugly and many more lines than I would like.
To remove rows from SortedDictionary by compare item N to N-1 in a dictionary and without use Linq, I propose the following solution :
1-Convert dictionary values into array.
2-Compare item N to N-1 in array.
3-Removing rows by index from dictionary.
'sd is your SortedDictionary
Dim sdArray(sd.Keys.Count - 1) As Integer
sd.Values.CopyTo(sdArray, 0)
For i = sd.Keys.Count - 1 To 1 Step -1
If sdArray(i) = sdArray(i-1) then
Dim index As Integer = 0
For Each p As KeyValuePair(Of DateTime, integer) In sd
if index = i then sd.Remove(p.Key) : Exit For
index += 1
Next
End If
Next
If you want the earliest dated item for any given unique value use this code :
For i = sd.Keys.Count - 1 To 1 Step -1
For j = i - 1 To 0 Step -1
If sdArray(i) = sdArray(j) then
Dim index As Integer = 0
For Each p As KeyValuePair(Of DateTime, integer) In sd
if index = i then sd.Remove(p.Key) : Exit For
index += 1
Next
Exit For
End If
Next
Next

Find and sum value of a datagridview column in vb.net

I want to find and sum qty value of searched id in data grid view column am using this code
Dim tqty As Double
For Each row As DataGridViewRow In dgv.Rows
If row.Cells.Item(0).Value = cmbItemCode.Text Then
tqty += row.Cells.Item(4).Value
Textbox1.text=tqty
Exit For
End If
Next
The problem is that Textbox1 shows only one top searched row value. For example
id item name qty
1 abc 4
2 xyz 10
1 abc 10
Textbox1 shows the Result only 4.
As soon as you hit the first value, you exit the for statement. Therefore you never get pass the first value. Erase the Exit For it should work.
If DataGridView2.RowCount > 1 Then
Dim tqty As Integer = 0
'if you have the other column to get the result you could add a new one like these above
For index As Integer = 0 To DataGridView2.RowCount - 1
amount += Convert.ToInt32(DataGridView2.Rows(index).Cells(2).Value)
'if you have the other column to get the result you could add a new one like these above (just change Cells(2) to the one you added)
Next
TextBox1.Text = tqty