How to count string occurences in a list(Of String) - vb.net

I am looking to dynamically count from a list, how many times items have occured. I can do it below if I specify the value I am looking for, but what I am really looking to do is to iterate through my list, count occurences, and total them out. My current code is below:
Dim itemlist As New List(Of String)
itemlist.add("VALUE1")
itemlist.add("VALUE2")
itemlist.add("VALUE3")
Dim count As Integer = 0
For Each value In itemlist
If value.Equals("VALUE1") Then count += 1
Next
Msgbox(count.tostring)
So my point would be instead of searching for the value, let the app total them up and display the counted occurences it to the user, similar to a "COUNTIF" in excel. I cant find much on this without using LINQ, Thanks

You can do this very easily with LINQ:
Msgbox(itemlist.Where(Function(value) value = "VALUE1").Count)
To count duplicates, once again it's easy with LINQ:
Dim itemlist As New List(Of String)
itemlist.Add("RED")
itemlist.Add("RED")
itemlist.Add("RED")
itemlist.Add("GREEN")
dim groups = itemList.GroupBy(Function(value) value)
For Each grp In groups
Console.WriteLine(grp(0) & " - " & grp.Count )
Next
Output:
RED - 3
GREEN - 1

Related

Refined list sorting by substring integer after alphabetical sorting

I have some information in a list (called listLines). Each line below is in a List(Of String).
1|This is just a header
3|This is just a footer
2|3456789|0000000|12312312313|BLUE|1|35.00
2|7891230|0000000|45645645655|BLUE|1|22.00
2|7891230|0000000|45645645658|RED|2|13.00
2|3456789|0000000|12312312316|RED|2|45.00
2|3456789|0000000|12312312317|YELLOW|5|-9.00
2|3456789|0000000|12312312315|ORANGE|3|15.00
2|7891230|0000000|45645645659|YELLOW|5|32.00
2|3456789|0000000|12312312314|GREEN|4|-20.00
2|7891230|0000000|45645645656|GREEN|4|39.00
2|7891230|0000000|45645645657|ORANGE|3|-18.50
I'm doing a listLines.sort() on the list to sort it alphabetically. Below is what I get after the .sort().
1|This is just a header
2|3456789|0000000|12312312313|BLUE|1|35.00
2|3456789|0000000|12312312314|GREEN|4|-20.00
2|3456789|0000000|12312312315|ORANGE|3|15.00
2|3456789|0000000|12312312316|RED|2|45.00
2|3456789|0000000|12312312317|YELLOW|5|-9.00
2|7891230|0000000|45645645655|BLUE|1|22.00
2|7891230|0000000|45645645656|GREEN|4|39.00
2|7891230|0000000|45645645657|ORANGE|3|-18.50
2|7891230|0000000|45645645658|RED|2|13.00
2|7891230|0000000|45645645659|YELLOW|5|32.00
3|This is just a footer
With that said, I need to output this information to a file. I'm able to do this ok. I still have a problem though. There is a sequence number in the above data at position 5 just after the listed colors (RED, BLUE, ETC..) that you can see. It's just before the last value which is a decimal type.
I need to further sort this list, keeping it in alphabetical order since position 2 is an account number and I want to keep the account numbers grouped together. I just want them to be resorted in sequential order based on the sequence number.
I was looking at another thread trying to figure out how I can do this. I found a piece of code like listLines.OrderBy(Function(q) q.Substring(35)).ToArray. I think this would probably help me if this was a fixed length file, it isn't however. I was thinking I can do some kind of .split() to get the 5th piece of information and sort it but then it's going to unalphabetize and mix the lines back up because I don't know how to specify to still keep it alphabetical.
Right now I'm outputting my alphabetical list like below so I can format it with commas and double quotes.
For Each listLine As String In listLines
strPosition = Split(listLine, "|")
Dim i As Integer = 1
Dim iBound As Integer = UBound(strPosition)
Do While (i <= iBound)
strOutputText = strOutputText & Chr(34) & strPosition(i) & Chr(34) & ","
i += 1
Loop
My main question is how do I re-sort after .sort() to then get each account (position1) in sequential order (position 5)? OR EVEN BETTER, how can I do both at the same time?
The List(Of T) class has an overload of the Sort method that takes a Comparison(Of T) delegate. I would suggest that you use that. It allows you to write a method or lambda expression that will take two items and compare them any way you want. In this case, you could do that like this:
Dim items = New List(Of String) From {"1|This Is just a header",
"3|This Is just a footer",
"2|3456789|0000000|12312312313|BLUE|1|35.00",
"2|7891230|0000000|45645645655|BLUE|1|22.00",
"2|7891230|0000000|45645645658|RED|2|13.00",
"2|3456789|0000000|12312312316|RED|2|45.00",
"2|3456789|0000000|12312312317|YELLOW|5|-9.00",
"2|3456789|0000000|12312312315|ORANGE|3|15.00",
"2|7891230|0000000|45645645659|YELLOW|5|32.00",
"2|3456789|0000000|12312312314|GREEN|4|-20.00",
"2|7891230|0000000|45645645656|GREEN|4|39.00",
"2|7891230|0000000|45645645657|ORANGE|3|-18.50"}
items.Sort(Function(x, y)
Dim xParts = x.Split("|"c)
Dim yParts = y.Split("|"c)
'Compare by the first column first.
Dim result = xParts(0).CompareTo(yParts(0))
If result = 0 Then
'Compare by the second column next.
result = xParts(1).CompareTo(yParts(1))
End If
If result = 0 Then
'Compare by the sixth column last.
result = xParts(5).CompareTo(yParts(5))
End If
Return result
End Function)
For Each item In items
Console.WriteLine(item)
Next
If you prefer a named method then do this:
Private Function CompareItems(x As String, y As String) As Integer
Dim xParts = x.Split("|"c)
Dim yParts = y.Split("|"c)
'Compare by the first column first.
Dim result = xParts(0).CompareTo(yParts(0))
If result = 0 Then
'Compare by the second column next.
result = xParts(1).CompareTo(yParts(1))
End If
If result = 0 Then
'Compare by the sixth column last.
result = xParts(5).CompareTo(yParts(5))
End If
Return result
End Function
and this:
items.Sort(AddressOf CompareItems)
Just note that this is rather inefficient because it splits both items on each comparison. That's not a big deal for a small list but, if there were a lot of items, it would be better to split each item once and then sort based on those results.

Get SUM of Unique Value in a collection

I'm looking to get the SUM of unique values in an excel worksheet using VB.net.
I am using a collection
So far my code gets me the Distinct Values, however I'm stumped on the Count side of things.
I feel like I'm close, but something is missing...
My data could look like:
Apple
Apple
Peach
Cherry
I'm looking for Results to be:
Apple 2
Peach 1
Cherry 1
This is where I am:
MySub:
Dim c, r As Range
Dim i As Integer
Dim dc As New Collection
Dim s As String
For Each c In r
dc.Add(c.Value, c.Value)
Next c
For i = 1 To dc.Count
s = dc.Item(i)
Next i
This produces my distinct list of values, but I'm not seeing how to obtain the SUM of those values.
Thanks for any pointers.
Assuming this really is VB.Net, you could use a Dictionary(Of String, Integer) like this:
Dim counts As New Dictionary(Of String, Integer)
For Each c In r
If Not counts.ContainsKey(c.Value) Then
counts.Add(c.Value, 0)
End If
counts.Item(c.Value) = counts.Item(c.Value) + 1
Next c
For Each pair In counts
Debug.Print(pair.Key & " " & pair.Value)
Next

Visual Basic- Random Numbers

I'm trying to generate 5 random numbers from 1-99 and display them in a ListBox. Can someone tell me where I'm going wrong? Right now my code is displaying all 99 numbers in the ListBox, but I only want 5 of them to display. Here is the code:
'list to store numbers
Dim numbers As New List(Of Integer)
'add desired numbers to list
For count As Integer = 1 To 99
numbers.Add(count)
Next
Dim Rnd As New Random
Dim SB As New System.Text.StringBuilder
Dim Temp As Integer
'select a random number from the list, add to listbox and remove it so it can't be selected again
For count As Integer = 0 To numbers.Count - 1
Temp = Rnd.Next(0, numbers.Count)
SB.Append(numbers(Temp) & " ")
ListBox2.Items.Add(numbers(Temp))
numbers.RemoveAt(Temp)
Next
Replace
For count As Integer = 0 To numbers.Count - 1
With
For count As Integer = 1 To 5
The above will work but, You need to add count just after your next statement as well. I recommend checking into learning more about loops as well. Clearly Visual Basic 2012 is great for that.

VB.Net form- Check for duplicate words a user entered textbox

Trying not to make this more complicated than it needs to be.
But I need to have a textbox and a button- when I click the button the code should count the words(i did this) and also display each word and how many times it appears in the string(aka textbox)
For example- Hello my name is Tom, Tom is good
Listbox
Hello 1
My 1
Name 1
is 2
Tom 2
good 1
Any help is appreciated, thanks(this is not for a test etc)
An alternate approach to indexOf would be to use a Dictionary to maintain the words and the counts. The benefit would be for large strings there would be less iterations than using indexOf as you could do something like:
1) Split the string (assuming this is just one loop through your string)
2) Iterate over the array once to count the number of occurrences of each word
Whereas with indexOf you'd need a fair few iterations to get through everything, depending on the size of your string
Dictionaries/Maps are nice data structures to know, in general. Here is a naive example as a console application:
Dim wordCount As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)()
Dim exampleString As String = "Hello my name is Tom, Tom is good"
Dim seperator() As String = {" ", ","}
Dim splitString() As String = exampleString.Split(seperator, StringSplitOptions.RemoveEmptyEntries)
For Each s As String In splitString
If wordCount.ContainsKey(s) Then
wordCount(s) = wordCount(s) + 1
Else
wordCount(s) = 1
End If
Next
For Each s As KeyValuePair(Of String, Integer) In wordCount
Console.WriteLine(s.Key + " " + s.Value.ToString())
Next
Console.ReadLine()
But the code does look a bit more complicated, I guess.
You could use VB.net IndexOf function with a loop to find the multiple instances of every word in the string and count them.
Just use a loop with the indexof function for every word you find in the whole string entered in the textbox.

Code optimisation removing duplicates in VB

I'm looking to optimise my code. Specifically this process
Calculate a group of locations (basically squares on a grid)
Have a list of all the locations that have been calculated
Then I go through all these locations, 1 at a time.
The issue I'm having is removing or not including duplicate locations in the list. I've tried having a list of integers (integers to represent the location) but it's still very slow. To give you an idea of the numbers: I'm talking at least 15,000 different location calculations and around 1,000,000 possible locations.
Any help on this would be much appreciated!
Here is how I remove duplicates from an string array, perhaps it will be of help to you:
Dim OneDimensionalTable(1000) As String
....
OneDimensionalTable = RemoveDuplicates(OneDimensionalTable)
.....
Private Function RemoveDuplicates(ByVal items As String()) As String()
Dim noDupsArrList As New ArrayList()
For i As Integer = 0 To items.Length - 1
If Not noDupsArrList.Contains(items(i).Trim()) Then
noDupsArrList.Add(items(i).Trim())
End If
Next
Dim uniqueItems As String() = New String(noDupsArrList.Count - 1) {}
noDupsArrList.CopyTo(uniqueItems)
Return uniqueItems
End Function