I have 64 panels, each containing two strings of data. For testing purposes I used a random number generator to provide my data.
I created a list of strings (64 strings total, containing "," separating the two pieces of data per panel) and now need to write them to each label.
I need to find a way to split the string data (which I know how) and write to each label.
For example: the first string will be split and added to the first panel called Label1a and Label1b, 2nd string split to Label2a and Label2b, etc..
Dim LotData As New List(Of String)
Dim randomnumber1 As Integer, randomnumber2 As Integer, randomchance As Integer
Dim slotnumber As String
Dim sbailes As String
Dim stemp As String
Randomize()
Dim n As Integer
For n = 1 To 64
randomnumber1 = CInt(Rnd() * 1000000000)
randomnumber2 = CInt(Rnd() * 300)
randomchance = CInt(Rnd() * 1000)
slotnumber = Convert.ToString(randomnumber1)
'approximately 50% of the lots will be empty in this test
If randomchance >= 500 Then
sbailes = CStr(randomnumber2)
Else
sbailes = "0"
End If
LotData.Add(slotnumber & "," & sbailes)
Next
My only solution is to write 128 lines of code, manually adding each string in but I know there must be a better solution than that...
You would want to get a control by string name. I have some methods that help to do this here (put them in a module)
<Extension()> _
Public Function ChildControls(ByVal parent As Control) As ArrayList
Return ChildControls(Of Control)(parent)
End Function
<Extension()> _
Public Function ChildControls(Of T)(ByVal parent As Control) As ArrayList
Dim result As New ArrayList()
For Each ctrl As Control In parent.Controls
If TypeOf ctrl Is T Then result.Add(ctrl)
result.AddRange(ChildControls(Of T)(ctrl))
Next
Return result
End Function
Public Function GetControlByName(ByRef parent As Control, ByVal name As String) As Control
For Each c As Control In parent.ChildControls
If c.Name = name Then
Return c
End If
Next
Return Nothing
End Function
Then in your method, you can get the control by name, depending on an integer counting from 1 to 64 like so:
For i As Integer = 1 To 64
CType(GetControlByName(Me, "Label" & i.ToString() & "A"), Label).Text = _
LotData(i).Split(",").FirstOrDefault()
CType(GetControlByName(Me, "Label" & i.ToString() & "B"), Label).Text = _
LotData(i).Split(",").LastOrDefault()
Next
Oh! You can also save yourself the trouble of adding all the controls to the form at design time by doing something like this:
For i As Integer = 1 To 64
Dim lblA As New Label()
Dim lblB As New Label()
lblA.Name = "Label" & i.ToString() & "A"
lblB.Name = "Label" & i.ToString() & "B"
' do something about Locations here
Me.Controls.Add(lblA)
Me.Controls.Add(lblB)
' you could even add them to your panel.controls
Next
(don't forget exception handling)
Related
Take a look at this picture. - http://www.imagebam.com/image/f544011007926944
I want to check in Textbox1, in the textbox2 enter the number and if there is that number I will appear in another text box. the problem occurs when in textbox1 there are numbers like 10,11, if I enter textbox2 number 1 then it will be taken as such, it will appear as if there is the number 1. I will only use for numbers from 1 to 80 .
where am I wrong?
' Split string based on space
Dim textsrtring As String = TextBox1.Text
Dim words As String() = textsrtring.Split(New Char() {" "c})
Dim found As Boolean = False
' Use For Each loop over words
Dim word As String
For Each word In words
If TextBox2.Lines(0).Contains(word) Then
found = True
If CheckVar1.Text.Contains(word) Then
Else
CheckVar1.Text = CheckVar1.Text + " " + TextBox1.Text()
End If
End If
So I think I know what you want. Your issue is the Compare Function on a String is comparing string literals and not numbers '11' contains '1' and '1' for Compare will return true that it contains a '1' in it. You need to convert the strings to numbers and then compare the numbers to each other.
Private Sub CompareNumbers()
'First Textbox that is to be used for compare
Dim textBox1Numbers As List(Of Integer) = GetNumbersFromTextLine(TextBox1.Text)
'Second Textbox that is to be used for compare
Dim textBox2Numbers As List(Of Integer) = GetNumbersFromTextLine(TextBox2.Text)
'Union List of Common Numbers (this uses a lambda expression, it can be done using two For Each loops instead.)
Dim commonNumbers As List(Of Integer) = textBox1Numbers.Where(Function(num) textBox2Numbers.Contains(num)).ToList()
'This is purely for testing to see if it worked you can.
Dim sb As StringBuilder = New StringBuilder()
For Each foundNum As Integer In commonNumbers
sb.Append(foundNum.ToString()).Append(" ")
Next
MessageBox.Show(sb.ToString())
End Sub
Private Function GetNumbersFromTextLine(sTextLine As String) As List(Of Integer)
Dim numberList As List(Of Integer) = New List(Of Integer)()
Dim sSplitNumbers As String() = sTextLine.Split(" ")
For Each sNumber As String In sSplitNumbers
If IsNumeric(sNumber) Then
Dim iNum As Integer = CInt(sNumber)
If Not numberList.Contains(iNum) Then
numberList.Add(iNum)
End If
Else
MessageBox.Show("Non Numeric Found in String :" + sTextLine)
End If
Next
Return numberList
End Function
I need to store the same item twice in a dictionary because say I have this sentence: 'Hi Example Test Hi' This should output 1, 2, 3, 1 as it needs to store the initial position with the word. Here is the code I have so far:
If System.Text.RegularExpressions.Regex.IsMatch(userInput.Text, "^[a-zA-Z\s]+$") Then
Dim userString As String = userInput.Text 'Refers to the textbox's text.
Dim count As Integer 'Declares the count variable, which will be added to the dictionary as the word's position.
Dim d As New Dictionary(Of String, Integer) 'Declares the dictionary I will iterate through in the future.
Dim d2 As New Dictionary(Of String, Integer)
Dim wordString = userString.ToLower().Split(" "c) 'Puts the input into lower case and splits it apart by detecting each space after each word.
For Each word In wordString
If (d.ContainsKey(word)) Then
Else
d.Add(word, count) 'Adds each word to the dictionary along with the position.
count = count + 1 'Adds to the count variable to iterate through the dictionary.
End If
Next
For Each de In d
For Each dee In d2
output.Text &= de.Value + 1 & ", " & dee.Value + 1 & ", " & Environment.NewLine 'Gathers each word from the dictionary, referencing it by using 'de' and retrieving the key and value.
Next
Next
Else
MessageBox.Show("Your Sentence Is Invalid, It Must Only Contains Letters.") 'Displays a message if the sentence they inputted is invalid.
End If
thanks,
Matt
maybe something like this:
Dim userString As String = "Hi Example Test Hi"
Dim count As Integer = 1 'Declares the count variable, which will be added to the dictionary as the word's position.
Dim d As New List(Of WordCountPos) 'Declares the dictionary I will iterate through in the future.
Dim wordString = userString.ToLower().Split(" "c) 'Puts the input into lower case and splits it apart by detecting each space after each word.
For Each word In wordString
If d.FindIndex(Function(x) String.Equals(x.Word, word)) <> -1 Then
d.Find(Function(x) String.Equals(x.Word, word)).Positions.Add(count)
Else
d.Add(New WordCountPos(word, 1, New List(Of Integer)({count}))) 'Adds each word to the dictionary along with the position
End If
count = count + 1 'Adds to the count variable to iterate through the dictionary.
Next
Dim output As String = ""
For Each de In d
output = String.Concat(output, Environment.NewLine, "Word: ", de.Word, " Count: ", de.Count, ", Positions:", String.Join("|", de.Positions.ToArray))
Next
Console.WriteLine(output)
Class:
Public Class WordCountPos
Public Sub New(w As String, c As String, pos As List(Of Integer))
Me.wcp_w = w
Me.wcp_c = c
Me.wcp_pos = pos
End Sub
Private wcp_w As String
Public Property Word() As String
Get
Return wcp_w
End Get
Set(ByVal value As String)
wcp_w = value
End Set
End Property
Private wcp_c As Integer
Public Property Count() As Integer
Get
Return wcp_c
End Get
Set(ByVal value As Integer)
wcp_c = value
End Set
End Property
Private wcp_pos As List(Of Integer)
Public Property Positions() As List(Of Integer)
Get
Return wcp_pos
End Get
Set(ByVal value As List(Of Integer))
wcp_pos = value
End Set
End Property
End Class
I would like all possible combinations from two string arrays.
Both arrays must have same length.
Result must keep order
For example :
dim lStr1() as string = {"One", "Two", "Three"}
dim lStr2() as string = {"EditOne", "EditTwo", "EditThree"}
dim res() as string = myAwesomeFunction(lStr1, lStr2)
// res :
One Two Three
One Two EditThree
One EditTwo Three
One EditTwo EditThree
EditOne Two Three
EditOne Two EditThree
EditOne EditTwo Three
EditOne EditTwo EditThree
It's like the binary composition of 2 arrays of strings.
Here's another solution. Since only 2 arrays are involved, we can bit-fiddle to get all of the "combinations". The & " " is just to format the output to match the example.
Private Function myAwesomeFunction(Array1() As String, Array2() As String) As String()
If Array1.Length <> Array2.Length Then
Throw New ArgumentException("Array lengths must be equal.")
End If
Dim combos(CInt(2 ^ Array1.Length) - 1) As String
For i As Integer = 0 To combos.Count - 1
For j = 0 To Array1.Length - 1
If (i And (1 << j)) > 0 Then
combos(i) += Array2(j) & " "
Else
combos(i) += Array1(j) & " "
End If
Next
Next
Return combos
End Function
The following code will produce the array in your example. It should work for any pair of input arrays. The function checks that the input arrays are of the same length.
The GetPermutations function is taken from a more general class I use for generating permutations of numbers. It returns arrays of total Integers between 0 and choose - 1, and being an Iterator function, it returns the next array each time it is called.
In order to match your example, I returned an array of String where each element is a single string consisting of each of the selected strings separated by spaces. You may find it more useful to return a List(Of String()) or even a List(Of List(Of String))
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lStr1() As String = {"One", "Two", "Three"}
Dim lStr2() As String = {"EditOne", "EditTwo", "EditThree"}
Dim res() As String = myAwesomeFunction(lStr1, lStr2)
End Sub
Function MyAwesomeFunction(lStr1() As String, lStr2() As String) As String()
Dim combos As New List(Of String)
If lStr1.Length <> lStr2.Length Then Throw New ArgumentException("Arrays must have the same length")
For Each combo() As Integer In GetPermutations(lStr1.Length, 2)
Dim elem As New List(Of String)
For i As Integer = 0 To combo.Length - 1
elem.Add(If(combo(i) = 0, lStr1(i), lStr2(i)))
Next
combos.Add(String.Join(" ", elem))
Next
Return combos.ToArray
End Function
Public Iterator Function GetPermutations(choose As Integer, total As Integer) As IEnumerable(Of Integer())
Dim totals() As Integer = Enumerable.Repeat(Of Integer)(total, choose).ToArray
Dim value(choose - 1) As Integer
Do
Yield value
For index As Integer = choose - 1 To 0 Step -1
value(index) += 1
If value(index) < totals(index) Then Continue Do
value(index) = 0
Next
Exit Do
Loop
End Function
Firstly, here's a pic on my report in design mode:
The underlying query for the report returns values like so:
Allen Nelli 3:A,5:B,7:A,8:A, etc.
Breton Micheline 1:A,3:A,5:B,7:A, etc
Caporale Jody 1:A,3:A,5:B,7:A, etc
I had to use a subquery to get the third field which concatenates the number : letter combinations. These values actually represent day of month and designation to a particular shift in a schedule. So basically, for a given month, each individual works the designated shift indicated by the day value.
The intention is to call a user defined public function named PopulateTextboxes(Value as String) to be called from the first textbox in the report from the textbox's ControlSource property. The third field in the query is actually named Expr1 and that is being passed as a parameter to the function. The function is designed to populate all the textboxes with the appropriate letter designation: A or B or C or D, etc. The function itself is not being fired when I run the report.
The function is as follows:
Public Function PopulateTextboxes(Expr As String) As String
'Each element of Expr should be a number followed by a colon followed by a letter: 10:A,12:B,15:C, etc.
Dim shiftData() As String
Dim Data As Variant
Dim i As Integer
Dim j As Integer
Dim temp() As String
Dim txt As TextBox
Dim rpt As Report
Dim strCtrl As String
If Expr = "" Then Exit Function
If IsNull(Expr) Then Exit Function
shiftData = Split(Expr, ",")
If UBound(shiftData) > 0 Then
'Make a 2D array
ReDim Data(UBound(shiftData), 2)
'Load up 2D array
For i = 0 To UBound(shiftData) - 1
If shiftData(i) <> "" Then
temp = SplitElement(shiftData(i), ":")
Data(i, 0) = temp(0)
Data(i, 1) = temp(1)
End If
Next i
Set rpt = Reports.item("Multi_Locations_Part_1")
If UBound(days) = 0 Then
MsgBox "days array not populated"
Exit Function
End If
'Populate each Textbox in the Multi_Locations_Part_1 Report
For i = 1 To UBound(days)
strCtrl = "txtDesig_" & CStr(i)
Set txt = rpt.Controls.item(strCtrl)
For j = 0 To UBound(Data) - 1
If Data(j, 0) = days(i) Then
txt.Value = Data(j, 1) 'A,B,C,etc.
Exit For
End If
Next j
Next i
End If
PopulateTextboxes = Expr
End Function
Private Function SplitElement(Value As String, Delim As String) As String()
Dim result() As String
result = Split(Value, Delim)
SplitElement = result
End Function
Please advise.
The best way is to call your function from the Format event of the Detail section, so it will be called for each record.
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
Call PopulateTextboxes(Me.Expr1)
End Sub
If PopulateTextboxes is in a separate module, I suggest to pass Me as additional parameter for the report, so you don't have to hardcode the report name.
Also note that you need the Set keyword when assigning object variables, e.g.
Set txt = rpt.Controls.item("txtDesig_" & CStr(i))
There are some good examples on how to calculate word frequencies in C#, but none of them are comprehensive and I really need one in VB.NET.
My current approach is limited to one word per frequency count. What is the best way to change this so that I can get a completely accurate word frequency listing?
wordFreq = New Hashtable()
Dim words As String() = Regex.Split(inputText, "(\W)")
For i As Integer = 0 To words.Length - 1
If words(i) <> "" Then
Dim realWord As Boolean = True
For j As Integer = 0 To words(i).Length - 1
If Char.IsLetter(words(i).Chars(j)) = False Then
realWord = False
End If
Next j
If realWord = True Then
If wordFreq.Contains(words(i).ToLower()) Then
wordFreq(words(i).ToLower()) += 1
Else
wordFreq.Add(words(i).ToLower, 1)
End If
End If
End If
Next
Me.wordCount = New SortedList
For Each de As DictionaryEntry In wordFreq
If wordCount.ContainsKey(de.Value) = False Then
wordCount.Add(de.Value, de.Key)
End If
Next
I'd prefer an actual code snippet, but generic 'oh yeah...use this and run that' would work as well.
This might be what your looking for:
Dim Words = "Hello World ))))) This is a test Hello World"
Dim CountTheWords = From str In Words.Split(" ") _
Where Char.IsLetter(str) _
Group By str Into Count()
I have just tested it and it does work
EDIT! I have added code to make sure that it counts only letters and not symbols.
FYI: I found an article on how to use LINQ and target 2.0, its a feels bit dirty but it might help someone http://weblogs.asp.net/fmarguerie/archive/2007/09/05/linq-support-on-net-2-0.aspx
Public Class CountWords
Public Function WordCount(ByVal str As String) As Dictionary(Of String, Integer)
Dim ret As Dictionary(Of String, Integer) = New Dictionary(Of String, Integer)
Dim word As String = ""
Dim add As Boolean = True
Dim ch As Char
str = str.ToLower
For index As Integer = 1 To str.Length - 1 Step index + 1
ch = str(index)
If Char.IsLetter(ch) Then
add = True
word += ch
ElseIf add And word.Length Then
If Not ret.ContainsKey(word) Then
ret(word) = 1
Else
ret(word) += 1
End If
word = ""
End If
Next
Return ret
End Function
End Class
Then for a quick demo application, create a winforms app with one multiline textbox called InputBox, one listview called OutputList and one button called CountBtn. In the list view create two columns - "Word" and "Freq." Select the "details" list type. Add an event handler for CountBtn. Then use this code:
Imports System.Windows.Forms.ListViewItem
Public Class MainForm
Private WordCounts As CountWords = New CountWords
Private Sub CountBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CountBtn.Click
OutputList.Items.Clear()
Dim ret As Dictionary(Of String, Integer) = Me.WordCounts.WordCount(InputBox.Text)
For Each item As String In ret.Keys
Dim litem As ListViewItem = New ListViewItem
litem.Text = item
Dim csitem As ListViewSubItem = New ListViewSubItem(litem, ret.Item(item).ToString())
litem.SubItems.Add(csitem)
OutputList.Items.Add(litem)
Word.Width = -1
Freq.Width = -1
Next
End Sub
End Class
You did a terrible terrible thing to make me write this in VB and I will never forgive you.
:p
Good luck!
EDIT
Fixed blank string bug and case bug
This might be helpful:
Word frequency algorithm for natural language processing
Pretty close, but \w+ is a good regex to match with (matches word characters only).
Public Function CountWords(ByVal inputText as String) As Dictionary(Of String, Integer)
Dim frequency As New Dictionary(Of String, Integer)
For Each wordMatch as Match in Regex.Match(inputText, "\w+")
If frequency.ContainsKey(wordMatch.Value.ToLower()) Then
frequency(wordMatch.Value.ToLower()) += 1
Else
frequency.Add(wordMatch.Value.ToLower(), 1)
End If
Next
Return frequency
End Function