DataGridViewRow numerically order - vb.net

How can I sort my DataGridViewRow to numerically order?
My code:
Dim Name As New List(Of String)
Dim Price As New List(Of Integer)
For x = 0 To Math.Max(Name.Count, Price.Count)
If x < Name.Count AndAlso x < Price.Count Then
Dim row As String() = New String() {Name(x), Price(x)}
DataGridView1.Rows.Add(row)
End If
Next
Price row example:
1345
1533
4555
6744

You've got them as two separate lists... I'll take a leap and make an assumption that you need to keep the source data in that format... Having them in two lists you've currently got a dependency on their positions. So use a sortable collection to pair them up
e.g.
Imports Microsoft.VisualBasic
Imports System.Collections.Generic
Imports System.Data.Linq
Dim Name As New List(Of String)
Dim Price As New List(Of Integer)
Dim Sortable As New List(Of KeyValuePair(Of String, Integer))
'Your checking that you weren't going past the last pair was an odd one
For x = 0 To Math.Min(Name.Count, Price.Count) - 1
'Pair them up so you can sort them together not having to try to match between two lists
Sortable.Add(New KeyValuePair(Name(x), Price(x)))
Next
'now you can sort it
Sortable = (From item In Sortable Order By Convert.ToInt32(item.Key) Select item).ToList()
'now stick it in the grid view, You might be able to base the grid view on the
'DataGridView1.DataSource = Sortable
'DataGridView1.DataBind()
'depends on how it is defined/configured,
'but for now let us return to your original code....
For Each kvp As KeyValuePair(Of String, Integer) In Sortable
Dim row As String() = New String() {kvp.Key, kvp.Value.ToString("$0.00")}
DataGridView1.Rows.Add(row)
Next

Related

vb.net word cloud indexing

I use a wordcloud based on a list of words and their frequencies. I load the list from a text file and display them in a Listview and image. When the textfile is not indexed (the highest frequencies first) the word cloud doesn't make the words with the highest counts the biggest.
Is there a way to load the words, highest frequencies first, without having to change the list?
Imports WordCloudGen = WordCloud.WordCloud
Imports System.IO
Public Class WordCloud
Private Sub WordCloud_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim lines = File.ReadLines("C:\Users\Gebruiker\Downloads\Words.txt")
Dim Words As New List(Of String) '({100})
Dim Frequencies As New List(Of Integer) '({100})
Dim textValue As String()
Dim items As New List(Of ListViewItem)
For Each line In lines
textValue = line.Split(New Char() {","})
Words.Add(textValue(0))
Frequencies.Add(Integer.Parse(textValue(1)))
items.Add(New ListViewItem(New String() {textValue(0).ToString, textValue(1).ToString}, 0))
Next
ListView1.Items.AddRange(items.ToArray)
Dim wc As WordCloudGen = New WordCloudGen(600, 400)
Dim i As Image = wc.Draw(Words, Frequencies)
ResultPictureBox.Image = i
End Sub
When the textfile is not indexed (the highest frequencies first) the word cloud doesn't make the words with the highest counts the biggest. Is there a way to load the words, highest frequencies first, without having to change the list?
I would recommend a new class to hold your data then you can sort anything you need much easier.
Create a new class: WordsFrequencies
Public Class WordsFrequencies
Public Property Word As String
Public Property Frequency As Integer
End Class
Change your WordCloud_Load routine as below:
Dim WordsFreqList As New List(Of WordsFrequencies)
For Each line As String In File.ReadLines("C:\Users\Gebruiker\Downloads\Words.txt")
Dim splitText As String() = line.Split(","c)
If splitText IsNot Nothing AndAlso splitText.Length = 2 Then
Dim wordFrq As New WordsFrequencies
Dim freq As Integer
wordFrq.Word = splitText(0)
wordFrq.Frequency = If(Integer.TryParse(splitText(1), freq), freq, 0)
WordsFreqList.Add(wordFrq)
End If
Next
If WordsFreqList.Count > 0 Then
' Order the list based on the Frequency
WordsFreqList = WordsFreqList.OrderByDescending(Function(w) w.Frequency).ToList
' Add the sorted items to the listview
WordsFreqList.ForEach(Sub(wf)
ListView1.Items.Add(New ListViewItem(New String() {wf.Word, wf.Frequency.ToString}, 0))
End Sub)
End If
In the above, I would recommend doing a simple For loop with File.ReadLines, this is so you don't have to load the whole file in memory if you're just getting data and parsing it. I'm using the OrderByDescending Method which is part of System.Linq namespace.
As far as this: Dim i As Image = wc.Draw(Words, Frequencies) you then could do something like:
Dim i As Image = wc.Draw(WordsFreqList.Select(Function(wf) wf.Word), WordsFreqList.Select(Function(wf) wf.Frequency))
This will project the Word's into an IEnumerable(String) and then Frequency into an IEnumerable(Integer).

VB NET: how to find a list of string which has max item count, from several list of string

Could you please help me for this:
I have 5 lists of string, lets say A, B, C, D, and E:
A has 6 items
B has 5 items
C has 9 items
D has 2 items
E has 7 items
I need to sort or to find, "C" as the list which has max items.
I need to create tab in winform and on every tab I need to create datagridview programmatically. the maximum count in the list will be the maximum tab I need to create. And on every tab, there will be 1 item of every list member. Of course not all tab will have item from member which has small item count.
Previously what Ii did is iterate through table and datagrid to construct and solve the problem to avoid sorting the list cause I have no idea to find the max items on those lists.
UPDATE: Helped by Andrew
` Dim z As New List(Of List(Of String))
Dim a As New List(Of String)
a.Add("a1")
a.Add("a2")
a.Add("a3")
Dim b As New List(Of String)
b.Add("b1")
b.Add("b2")
b.Add("b3")
b.Add("b4")
b.Add("b5")
Dim c As New List(Of String)
c.Add("c1")
c.Add("c2")
c.Add("c3")
c.Add("c3")
z.Add(a)
z.Add(b)
z.Add(c)
Dim maxItems = z.Max(Function(p) p.Count)
MessageBox.Show(maxItems)`
If all you need is the length of the longest list...
Private A As New List(Of String) From {"Mathew", "Mark", "Luke", "John"}
Private B As New List(Of String) From {"Apples", "Oranges", "Pears"}
Private C As New List(Of String) From {"Haddock", "Salmon"}
Private D As New List(Of String) From {"Great Dane", "Poodle", "Bulldog", "Spaniel", "Golden Retriever"}
Private Sub GetMaxListLength()
Dim E() As Integer = {A.Count, B.Count, C.Count, D.Count}
Dim max = E.Max
MessageBox.Show(max.ToString)
End Sub
Both Mary answer and Andrew's work perfectly:
Dim z As New List(Of List(Of String))
Dim a As New List(Of String)
a.Add("a1")
a.Add("a2")
a.Add("a3")
Dim b As New List(Of String)
b.Add("b1")
b.Add("b2")
b.Add("b3")
b.Add("b4")
b.Add("b5")
Dim c As New List(Of String)
c.Add("c1")
c.Add("c2")
c.Add("c3")
c.Add("c3")
z.Add(a)
z.Add(b)
z.Add(c)
Dim eb() As Integer = {a.Count, b.Count, c.Count}
Dim max = eb.Max
Dim maxItems = z.Max(Function(p) p.Count)
MessageBox.Show(max)

Add Items to datatale per column instead of per row

Half a day of searching made at least my data readable in a datagrid in a wpf app.
My problem is (or what in think is my problem) would be the adding of data in the columns I created.
My source of data is from a dictionary of string, list(of string) with my dictionary key as the header and the List as it's items, also the dictionary and it's content has no fixed length.
And to display my data I used the combination of DataTable and DataGrid
Here's my snippet
Dim files As New Dictionary(Of String, List(Of String))
Dim dt As New DataTable
For Each item As KeyValuePair(Of String, List(Of String)) In files
dt.Columns.Add(item.Key)
For Each file As String In item.Value
Dim dr As DataRow = dt.NewRow
dr(dt.Columns(item.Key).Ordinal) = file
dt.Rows.Add(dr)
Next
Next
DGrid.ItemsSource = dt.AsDataView
It works(somewhat), but as you all have guessed all the succeeding displayed column items after the last one starts where it ended last(looks like a stair).
so the question is do I have to change the way I store my data(dictionary) or I am missing something and this can work as there is a way to add data per column instead of rows?
UPDATE
It's not pretty and I know there is a better solution out there.
What I did first was to just render/instantiate the table and it's content
Dim dt As New DataTable
For Each item As KeyValuePair(Of String, List(Of String)) In files
dt.Columns.Add(item.Key)
For Each file As String In item.Value
Dim dr As DataRow = dt.NewRow
dr(item.Key) = Nothing
dt.Rows.Add(dr)
Next
Next
Then edit it's content:
For Each item As KeyValuePair(Of String, List(Of String)) In files
For file_index As Integer = 0 To item.Value.Count - 1
dt.Rows(file_index)(item.Key) = item.Value(file_index)
Next
Next
This is a bad solution but it works. Is there a better way?
you need to reuse existing rows for this. And add new one only when you have more items then rows.
Dim Files As New Dictionary(Of String, List(Of String))
Dim T As New DataTable, R As DataRow
For Each Pair As KeyValuePair(Of String, List(Of String)) In Files
T.Columns.Add(Pair.Key)
For i As Integer = 0 To Pair.Value.Count - 1
If i < T.Rows.Count Then
R = T.Rows(i)
Else
R = T.NewRow()
T.Rows.Add(R)
End If
R(Pair.Key) = Pair.Value(i)
Next
Next

I am unsure about how to remove cases from the "select case" statement in visual basic after a certain case has been selected more than 3 times

I've a word guessing game in development. It works so that when the play button is clicked, a random number between 1 and 20 will be generated. This new randomly generated number will then go into the select case statement as shown in the code below:
Dim RND As New Random
Dim rndNumber As String
rndNumber = RND.Next(1, 20)
Dim RndWord as string
Dim RndHint as string
select case(rndnumber)
case 1
RndWord = "hockey"
RndHint = "A ball game played with curved, wooden sticks"
Case 2
RndWord = "dinghy"
RndHint = "This is a small boat usually made out of rubber"
These are just 2 out of 20 similar cases.
The selected case contains a word and a hint that will be displayed upon that case being selected. My problem is, how do I remove a case after it has been selected three times; removing the word and the hint from the program completely so that they won't appear again. I've looked into different types of arrays; however, after 2 hours of research and many attempts at using them they don't seem to fit this purpose.
Firstly remove your case statement, it makes is less manageable. What if tomorrow you decide to add 5 more questions? You will end up changing the code. You can keep all the data externally and have them read into a dictionary object.
Define these at class level:
Dim questions As Dictionary(Of Integer, KeyValuePair(Of String, String)) = New Dictionary(Of Integer, KeyValuePair(Of String, String))()
Dim questionAppearedCount As Dictionary(Of Integer, Integer) = New Dictionary(Of Integer, Integer)()
Create new Sub with this:
Public Sub FillQuestions()
questions.Add(1, New KeyValuePair(Of String, String)("hockey", "A ball game played with curved, wooden sticks"))
questions.Add(2, New KeyValuePair(Of String, String)("dinghy", "This is a small boat usually made out of rubber"))
'Also, you may use File.ReadAllLines() to fill from a file.
End Sub
Finally, BtnGenerate_Click
Dim rnd As Random = New Random()
Dim rndNumber As Integer = rnd.[Next](1, 20)
If questionAppearedCount.ContainsKey(rndNumber) Then
questionAppearedCount(rndNumber) = questionAppearedCount(rndNumber) + 1
Else
questionAppearedCount.Add(rndNumber, 1)
End If
If questionAppearedCount(rndNumber) > 3 Then
'do not show question, instead get Next random
Else
return question(rndNumber)
End If
Here is the code, so I keep questions in dictionary, show them using dictionary.
In the above code, question can be read from external file using File.ReadAllLines()
When question is shown, add to the count and if count is > 3, don't show.
Make an array to count each case.
If the count is 3 you loop.
If less you increase the counter in the array and exit the loop so it ll use a case statement.
Be carreful in this case if all counters reach 3 the program wil loop infinitively.
Else an array for all the cases data.
When 3 is reached the datas are moved at the end of the array and the max index is decreased by one. At beginning its 20... next 19.. etc...
I recommend this code.
My sample also has a list of questions.
A very important differences though:
It does the filtering of the data BEFORE the random call. So, it's only searching for the questions that are valid. In certain cases, repeated random calls very close together might produce the same result, so this verifies you only do it once.
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Linq
Public Module Module1
Dim questionAppearedCount As Dictionary(Of Integer, Integer)
Public Sub Main()
Dim questions As Dictionary(Of Integer, KeyValuePair(Of String, String)) = New Dictionary(Of Integer, KeyValuePair(Of String, String))()
questions.Add(1, New KeyValuePair(Of String, String)("hockey", "A ball game played with curved, wooden sticks"))
questions.Add(2, New KeyValuePair(Of String, String)("dinghy", "This is a small boat usually made out of rubber"))
questionAppearedCount = New Dictionary(Of Integer, Integer)()
SelectQuestion(1)
SelectQuestion(1)
SelectQuestion(1)
' Get the Filtered List
Dim filteredQuestions() as KeyValuePair(Of Integer, KeyValuePair(Of String, String)) = questions.Where(Function(ByVal item as KeyValuePair(Of Integer, KeyValuePair(Of String, String))) Not questionAppearedCount.ContainsKey(item.Key) OrElse questionAppearedCount(item.Key) < 3).ToArray()
Dim rand As New Random
Console.WriteLine(filteredQuestions(rand.Next(0, filteredQuestions.Count - 1)).Value)
End Sub
Public Sub SelectQuestion(ByVal questionNumber as Integer)
' Add Question
If questionAppearedCount.ContainsKey(questionNumber) Then
questionAppearedCount(questionNumber) += 1
Else
questionAppearedCount(questionNumber) = 1
End If
End Sub
End Module
And here's some vb.net helper code that you can use to REFACTOR your case statements automatically. Just paste your code into it and it will return the equivalent code to the console. You'll replace your code with this code.
Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Linq
Public Module Module1
Dim questionAppearedCount As Dictionary(Of Integer, Integer)
Public Sub Main()
'Dim questions as New Dictionary(Of Integer, KeyValuePair(Of String, String))
For rndnumber as Integer = 1 to 20
Dim RndWord as String = ""
Dim RndHint as String = ""
select case(rndnumber)
case 1
RndWord = "hockey"
RndHint = "A ball game played with curved, wooden sticks"
Case 2
RndWord = "dinghy"
RndHint = "This is a small boat usually made out of rubber"
end SElect
If Not String.IsNullOrEmpty(rndword) Then
'questions.Add(rndnumber, new KeyValuePair(Of String, String)(rndword, rndhint))
Console.WriteLine("questions.Add(" & rndnumber & ", new KeyValuePair(Of String, String)(""" & rndword.Replace("""", """""") & """,""" & RndHint.Replace("""", """""") & """))")
End If
Next
End Sub
End Module

vb.net - multi-dimension array list

I've managed to make some single dimension array lists but I can't figure out a multi dimension arraylist.
Here's what I'm trying to do:
I have a database (mdb) with 5 columns that I want each row to be in an array list.
In PHP what I'd typically do is:
$array[$field1] = array($field2,$field3,$field4,$field5);
How I do the same in vb.net so anytime I need to fetch an item for a specific for the row1 I could call it?
For a single dimension I could do the following, but I can't figure out how to add more fields to a single array row:
Dim tmpArrayX As New ArrayList
tmpArrayX.Add(field(0))
tmpArrayX.Add(field(1))
etc...
If you want to use ArrayList, just make it's items contain other ArrayLists.
Or you could use normal arrays as:
Dim multiArray(2, 2) As String
multiArray(0, 0) = "item1InRow1"
multiArray(0, 1) = "item2InRow1"
multiArray(1, 0) = "item1InRow2"
multiArray(1, 1) = "item2InRow2"
Though my personal preference would be to use List as:
Dim multiList As New List(Of List(Of String))
multiList.Add(New List(Of String))
multiList.Add(New List(Of String))
multiList(0).Add("item1InRow1")
multiList(0).Add("item2InRow1")
multiList(1).Add("item1InRow2")
multiList(1).Add("item2InRow2")
Edit: How to find row:
Dim listIWant As List(Of String) = Nothing
For Each l As List(Of String) In multiList
If l.Contains("item1InRow2") Then
listIWant = l
Exit For
End If
Next
' This allows adding rows on the fly....Tested and it works!
Dim multiList As New List(Of List(Of String))
Dim ListRow As Integer = 0
For each record in some_source
dim Country as string = record.country 'from some source
dim Date as Date = record.Date 'from some source
dim Venue as string = record.Venue 'from some source
dim Attendance as string = record.Attendance 'from some source
multiList.Add(New List(Of String))
multiList(ListRow).Add(Country)
multiList(ListRow).Add(Date)
multiList(ListRow).Add(Venue)
multiList(ListRow).Add(Rating)
multiList(ListRow).Add(Attendance)
ListRow = ListRow + 1
next