I have been attempting many ways to retrieve 2 collections together, while the first collection holds a comma-separated value in a column, we can not find a solution to passing the first collection value to the second For Each.
This code simply retrieves database rows and adds each result to our list control using the Add() method.
Dim transferstable As New DataTable
count = 0
For Each row As DataRow In transferstable.Rows
Dim name = Truncate(row.Item("name"), 42)
ListControl1.Add(name, row.Item("username")", row.Item("added"), avatars, row.Item("online"), images(count), 0)
count += 1
Next
Problem
We need to nest the loops, so we get the value from the first collection from the "avatars" column (image1,image2,image3) and call it from Add() - 4th parameter.
We only get always 1 string result into the view, while the actual query reports many rows with 2 strings (image1, image2) so I tried this:
Dim lst As New List(Of String) From {
transferstable.Rows(0).Item(8)
}
count = 0
For Each item As String In lst
For Each row As DataRow In transferstable.Rows
Dim name = Truncate(row.Item("name"), 42)
ListControl1.Add(name, row.Item("username")", row.Item("added"), item, row.Item("online"), images(count), 0)
count += 1
Next
Next
And the still the same single result! (8) is the GROUP_CONCAT column for "avatars" How do we pass this list over to the 4th parameter?
We want to retrieve these as URL remote images and render them to view with Bitmap.
Expected result:
A list of 15x15 pictures that represent each split result from GROUP_CONCAT(avatars)
I've been at all different ways to do this for most of the day, I know nesting is the right direction but I can't figure out why only 1 result is coming back (image1 - not image1,image2, etc.)
Some physical image files do not exist anymore, so rendering that to view also has it halt after a few single string results, so it quits and gives an error, like a 404 but does not proceed with the 180 other rows.
https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/for-each-next-statement
Related
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.
I have a query that returns a list of items that are in one listbox but not another. I want to put the results of that into a different listbox, problem is that when I try to put the results into a listbox, it puts them all on the same line. Say it returns three results (project_green Project_blue_ project_red), its adding them to one line in the list box as (project_greenproject_blueproject_red). I want each item to be on its own line but I can't get it there.
Here is the code I have
Dim result As List(Of String) = (From s1 As String In Me.ListBox1.Items Where Not Me.ListBox4.Items.Contains(s1) Select s1).ToList()
ListBox5.Items.Add(String.Join(Environment.NewLine, result))
Any help would be appreciated.
Thanks
Dim result = From s1 As String In ListBox1.Items Where Not ListBox4.Items.Contains(s1) Select s1
ListBox5.Items.AddRange(result)
This also saves you a bunch of extra memory. There's no need to allocate a List when the IEnumerable result form the linq query will already do on its own.
Though personally, I'm not a fan of the query comprehension syntax and prefer to write it this way:
Dim result = ListBox1.Items.Where(Function(s1) Not ListBox4.Items.Contains(s1))
ListBox5.Items.AddRange(result)
I am using a Dictionary to create a key to a List Of DataRow. I want to iterate through each key and remove rows in the List. This will throw an out of range exception when I explicitly try to remove a row. How can I alter my code to accomplish this?
For Each g As KeyValuePair(Of [String], List(Of DataRow)) In grouped
For Each row As DataRow In g.Value
If CInt(segment(1)) <= 4 Then
'THIS THROWS AN OUT OF RANGE EXCEPTION
g.Value.Remove(row)
End If
Next
Next
I only want to remove specific rows based on criteria. Can someone post an example? I am on an old browser the "add comment" function does not work
Can you show a code example of how to use a predicate based on row.Item("ID") with the RemoveAll function?
I tried this and am getting an exception
g.Value.RemoveAll(Function(l) l.Item(Con.ID) Is l.Item(Con.ID).ToString)
Use List.RemoveAll. Not only will this make the act of removing all of the items easier than trying to remove items in some form of looping construct, but it will be dramatically more efficient as the List can reorganize all of the items once at the end, rather than moving the items down one index at a time over and over.
I figured it out using a reverse For loop. I did not see an examlpe on how to use the RemoveAll. Please post an example if you have time
For i As Integer = g.Value.Count - 1 To 0 Step -1
Dim row As DataRow = CType(g.Value(i), DataRow)
Dim segment() As String = row.Item(c._ID).ToString.Split("-"c)
If CInt(segment(1)) <= 4 Then
g.Value.Remove(row)
End If
Next i
I am developing a program for a chain of restaurants, they should normally be able to calculate their guestcount and sales through a vb.net application with a connection to dbf files.
My dataset gets filled in correctly as is my datatable (checked by filling in datarowview = right data)
But then I get a problem, in all my functions using my datatable, the datatable skips the final value, in this case it is all values from a month so it either skips 31 or day 30.
Tried while, Tried for each, debugged alot (how i found it was the last value). But now I have no idea why the last value isn't used by the function
Public Function Getgctakeout(ByVal i_table As DataTable)
table = i_table
i = 0
gctakeout = 0
For Each row As DataRow In i_table.Rows
gctakeout = gctakeout + Convert.ToDouble(row(4))
Next row
'MessageBox.Show(gctakeout)
Return gctakeout
End Function
This function does not use the value of the last row to calculate gctakeout
what in the name of the lord is wrong :)
Assuming that your DataTable is really filled correctly, you have two other options to get the sum.
Use the old DataTable.Compute method which works also with .NET < 2.0
Use Linq-To-DatSet and it's Enumerable.Sum
1)
Dim Sum = CType(table.Compute("Sum(ColumnName)", Nothing), Double)
2)
Dim Sum = table.AsEnumerable().
Sum(Function(row)row.Field(Of Double)("ColumnName"))
Basically I have and array of integers that vary in size. I need to compare each number to each other number and display which number is repeated. For example:
Dim ints() As Integer = {1,2,2,5,4,6}
The number that shows up more than once is 2.
How can I run through the array and compare each integer with the numbers in the array. I tried a for loop but it didn't return the value I was looking for. I am new to VB.NET and do not understand fully.
Dim ints() As Integer = {1,2,2,5,4,6}
Dim repeatedNumbers = ints.GroupBy(Function(intValue) intValue) _
.Where(Function(grp) grp.Count > 1)
For each grp in repeatedNumbers
Console.WriteLine("Number {0} is repeated {1} times", grp(0), grp.Count)
Next
What this code does:
We first call GroupBy, which groups items by their value. The Function gets the grouping key, in this case we simply group by the array's value itself. This call returns a sequence of
groups. There is one group for every unique value in the array. The
group contains all items that correspond to a unique value. So if a value appears twice in the array, there will be a group which contains two ints with this value.
We call Where to filter groups. We only want groups for which the count is greater than one, so that only duplicate values are considered.
We then loop through the result. grp(0) gives us the first number in the group (we could have picked any number in the group, since all numbers in a group are the same!) and the Count property gives us the number of repetitions.
I would try it with something like this:
Dim ints() As Integer = {1, 2, 2, 5, 4, 6}
Array.Sort(ints)
For i = 1 To ints.GetUpperBound(0)
If ints(i) = ints(i - 1) Then MessageBox.Show(String.Format("{0} is repeated", ints(i)))
Next
Doing it like this on a sorted array keeps down the nesting.
I've not tested this but it should be along the right lines.
You could use LINQ to find the duplicates:
Dim repeating = (From n In ints
Group By n Into Dups = Group
Where Dups.Count > 1
Select Dups.First).ToArray()
This returns an Array of integers which only contains numbers that are not unique in the original array.
So this displays the repeating number(s):
MessageBox.Show(String.Format("Duplicates found: {0}", String.Join(","c, repeating)))