Function does not read last value - vb.net

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"))

Related

How to pass Value from Last Loop?

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

inquiry Data from data table to datagridview with filters

i have datatable "dataitems" contain 98000 Rows And Datagridview have 11000 row
want to add the quantity form the datatable to the datagridview every item in it's row in the datagrid view
i am using this code but its take too too too much time to run and sometimes stop responding i need ideas to make it faster to run
Dim dt As New DataTable = najrndataset.dataitems
Dim Total As Integer
for x = 0 to datagridview1.rows.count -1
Dim b = datagridview1.rows(x).cells(1)
Dim c = 3
Total = (From r As DataRow In dt.AsEnumerable
Where r.Field(Of String)("Item_Number") = b And r.Field(Of Integer)("SOP_Type") = c
Select r.Field(Of Integer)("Quantity")).Sum
datagridview1.Rows(x).Cells(0).Value = Total
next
Hopefully you appreciate that if you have 11000 rows in a datagridview (terrible idea, by the way) and 98000 rows in a datatable, and you're running a loop that searches the table for each of the 11K items, and it does this by starting at number 1, and searching 98000 items for it, then going to 2 and searching 98000 items for it til you reach 11000 and searching 98000 items for it... At the end of the operation you're going to have performed 11000 x 98000 operations.. i.e. you're going to have performed 1.078 BILLION operations. This is why "its take too too too much time to run and sometimes stop responding" :)
You can speed this up by using a dictionary to track the sums, and it'll probably be fastest to index the 98000 items then set the dictionary from them:
Dim d as New Dictionary(Of String, Integer)
For Each di In najrndataset.dataitems.Where(Function(r) r.SOP_Type = 3)
If Not d.ContainsKey(di.Item_Number) Then
d(di.Item_Number) = di.Quantity
Else
d(di.Item_Number) += di.Quantity
End If
Next di
Then edit your grid (ugh; this isn't how datagridview are supposed to be used)
datagridview1.SuspendDrawing()
For x = 0 to datagridview1.rows.count - 1
Dim b = datagridview1.rows(x).cells(1)
Dim s As Integer
If d.TryGetValue(b, s) Then
datagridview1.rows(x).cells(0) = s
End If
Next x
datagridview1.ResumeDrawing()
You could also have a logic of "loop over the datagrid, putting 11000 items in the dictionary, loop over the datatable accumulating sums into the dictionary if the keys are present in the dictionary, loop over the datagriview putting the sums into the datagridview".
Not an answer, but too long for a traditional comment. I'm working to provide an answer separately.
I can't tell you how many times I've seen code like this:
Dim someVariable As New SomeObject
someVariable = someMethodToReturnSomeObject()
This pattern is bad code!
The New operator in the first line tells the compiler you want to allocate memory and run the constructor for your type. However, the next line assigns a new object... it throws away and forgets the memory and constructor work from the previous line. That's wasteful.
Instead, you want this:
Dim someVariable As SomeObject = someMethodToReturnSomeObject()
Worse, this speaks to a profound lack of understanding of the difference between a reference and an object, and what the computer is doing with your code in memory. This is a core principle of how many programming environments work. Code like the first example gives me big doubts of the capability of the programmer who writes it.

Reference another cell in the same row having calculated the minimum value in a datatable column

Using VB, I've used the following line to successfully find the minimum value in a specific column (say column 5, where the values are all of double) in a datatable:
Dim test as double
test = datatable.Compute("min(sourcecolumn)", "")
I would now like to refer to the values in other columns (let's say column 2) along the row containing that minimum column value.
Any help would be much appreciated as I can't get my head round it!
Thanks
You can use the DataTable.Select() method to get the row(s) that contain the minimum value. DataTable.Select() returns a DataRow(). In the code below, I assumed only one column contains the minimum value hence Data(0).
Dim test as double
test = datatable.Compute("min(sourcecolumn)", "")
Dim Data() As DataRow = datatable.Select("sourcecolumn = " & test.ToString())
Dim column2 = Data(0)(1)
All you have is a value but you currently have no idea what row(s) contain that value. You can use the table's Select method to get the row(s) that contain that value in that column. Once you have the row(s), you can do whatever you want with it/them:
Dim minValue = CDbl(myDataTable.Compute("MIN(MyColumn)", Nothing))
Dim rows = myDataTable.Select($"MyColumn = {minValue}")
For Each row In rows
'Use row here.
Next
Select always returns an array, even if there is only one row, so the loop will always work. If you know that there will never be more than one match, you can just get the first element directly.

Can I use a method that returns a list of strings in SSRS report code as the headers in a tablix?

I have table that needs to contain 50 columns for each half hour in the day (+2 for daylight savings). So each column will be HH1, HH2, HH3... HH50.
I have written this piece of code in the report properties code section.
Function GetHH() As List(Of String)
Dim headers As List(Of String) = new List(Of String)
For index As Integer = 1 to 50
headers.Add("HH" & index)
Next
return headers
End Function
Is there a way to use the output of this function as the headers of my tablix? Or will I need to add the headers to some sort of dataset in the database and add it from there?
The column group functionality would be well suited for this. As you mentioned, you would need to write a SQL statement to return these values in a dataset. Then you can set your column group to group on these values. This way your table always gets the right number of columns and you don't have to add them manually.

Averaging numerous values in a class

I have a class with a lot of parameters as it takes in all the columns in Excel, since this is the first step I usually do when building a macro. Then I started to think about how to actually accomplish what I'm trying to do and I think I just wasted a couple of hours of coding.
What I am trying to do is average each of the parameters inside the class as well as trying to get minimum and maximum values. There are about 100000 rows in these excel files.
My plan was to put everything into a collection and then I was thinking there was going to be some sort of averaging function or a min and max function for the collection parameter, or a way to send an array to a function that can calculate min or max.
What would be ideal:
Dim collectionOfRecords as new collection
for each row in sheet.rows
Dim r as New RmmRecord
call r.PopulateClass(row)
collectionOfRecords.add r
next row
Then get the average from the collection somehow like this:
dim parameter1Average as double
parameter1Average = collectionOfRecords.Parameter1.Average '(ha, I wish)
OR:
parameter1average = GetAverageFromCollection(collectionOfRecords, Parameter1)
Public Function GetAverageFromCollection(records as Collection, parameterToAverage as something??)
for each record in records
sum = record.parameterToAverage + sum
next record
GetAverageFromCollection = sum / records.count
end function
Thank you!