I have the follow custom function that I am using in an SSRS report in order to calculate an average value using the LookUpSet function. I have a number of results in the set that are returned that are null. At the moment this function is taking these as 0 and increasing the count. How would I modify this to exclude the 0 values so that it just skips them and keeps the count the same. ie. just excludes them completely from the dataset that is returned?
Function AvgLookup(ByVal items As Object()) As Decimal
If items Is Nothing Then
Return Nothing
End If
Dim suma As Decimal = New Decimal()
Dim ct as Integer = New Integer()
Dim Avg as Decimal = New Decimal()
suma = 0
ct = 0
For Each item As Object In items
suma += Convert.ToDecimal(item)
ct += 1
Next
Avg = suma / ct
If (ct = 0) Then return 0 else return Avg
End Function
It seems the easiest way would be to add a IF statement in your loop. This assumes it is converting the NULLS to 0 and you have no 0 values you want.
For Each item As Object In items
IF Convert.ToDecimal(item) <> 0
suma += Convert.ToDecimal(item)
ct += 1
ENDIF
Next
Related
I have a datatable that has the columns: Order Number, a count of Lines, and a sum of Units. I want to end up with charts shown here. 3 charts Each shows a column for 1 through 20 and then >20
The problem is looping through the datatable takes over 1.5 minutes.
Dim XAxis(21) As String
Dim LinesPO(21) As Integer 'Lines per Order
Dim UnitsPO(21) As Integer 'Units Per Order
Dim UnitsPL(21) As Integer 'Units Per Line
For Each Dr As DataRow In LivesqlDt2.Rows
For i = 0 To 21
If i < 21 Then
XAxis(i) = i.ToString
If Dr.Item("Lines") = i Then LinesPO(i) += 1
If Dr.Item("Units") = i Then UnitsPO(i) += 1
If Math.Round(Dr.Item("Units") / Dr.Item("Lines"), 0) = i Then UnitsPL(i) += 1
Else
XAxis(i) = ">20"
If Dr.Item("Lines") >= i Then LinesPO(i) += 1
If Dr.Item("Units") >= i Then UnitsPO(i) += 1
If Math.Round(Dr.Item("Units") / Dr.Item("Lines"), 0) >= i Then UnitsPL(i) += 1
End If
Next
Next
I'm looking for any good ideas to speed this up, because the salesman wants to be able to run this in front of their customer.
I have a datagridview with data I pull from an SQL Server. It comes back with some data that are duplicates. I want to remove all the duplicates but keep count of how many there are of each unique items. Here is an example of what the data looks like...
For intI = DataGridView1.Rows.Count - 1 To 0 Step -1
For intJ = intI - 1 To 0 Step -1
If DataGridView1.Rows(intI).Cells(1).Value =
DataGridView1.Rows(intJ).Cells(1).Value AndAlso
DataGridView1.Rows(intI).Cells(3).Value =
DataGridView1.Rows(intJ).Cells(3).Value Then
DataGridView1.Rows.RemoveAt(intI)
Exit For
End If
Next
Next
So I can remove all the duplicates, but I want to be able to have a count of all the items in the end, including the duplicates. For example, There are 5 CA, I want to remove 4 leaving just 1 unique one, but I want to show that there are 5 CA in my datagridview next to California.
So in the end, I want the datagridview to have something like :
State | Short
California | 5
Here is my Query:
DECLARE #StartDate DATETIME
DECLARE #EndDate DATETIME
SELECT
States , Shorts
FROM
DAT.States
INNER JOIN
DATR.[Shorts]
WHERE #StartDate IS NULL
Thank you for your help!
EDIT:
I came up with a method of counting the GridView1 into GridView2 but I'm not exactly sure on the code. Maybe I could get some help with this part instead?
For i As Integer = DataGridView1.RowCount - 1 To 1 Step -1
For j As Integer = DataGridView2.RowCount - 1 To 1 Step -1
'If Grid2.Row(j).Cells(1).Value = Grid1.Rows(i).Cells(1).Value Then
' Grid2 already has that value, +1 to Column 2 of Cell(j)
' Delete row(i)
'Else
'Value does not exist, add row(i) into Grid2, and in the 2nd column of Grid2, the count is 1
'End If
Next
Next
The end result for GridView2 would be something like :
Here is my code I came up with to try and count the States in Column 1 and then delete it and add it to the Grid2, but it's not working...
Dim Counts As Integer = 0
Dim State As String = ""
Dim CurLoop As Integer = 0
Do Until CurLoop > DataGridView1.RowCount - 1
State = DataGridView1.Rows(CurLoop).Cells(0).Value
For i As Integer = DataGridView1.RowCount - 1 To 1 Step -1
If DataGridView1.Rows(i).Cells(0).Value = State Then
Counts += 1
DataGridView1.Rows.RemoveAt(i)
End If
Next
DataGridView2.Rows.Add(State, Counts)
State = ""
Counts = 0
CurLoop += 1
Loop
I have figured out the answer to my own question. It's not the prettiest solution but it works. If anyone else is in need of something like this, here is what I did...
Dim Counts As Integer = 0
Dim State As String = ""
Dim CurLoop As Integer = 0
Do Until CurLoop > DataGridView1.RowCount - 1
State = DataGridView1.Rows(CurLoop).Cells(0).Value
For i As Integer = DataGridView1.RowCount - 1 To 1 Step -1
If DataGridView1.Rows(i).Cells(0).Value = State Then
Counts += 1
DataGridView1.Rows.RemoveAt(i)
End If
Next
DataGridView2.Rows.Add(State, Counts)
State = ""
Counts = 0
CurLoop += 1
Loop
Counts = DataGridView2.Rows(0).Cells(1).Value
Counts += 1
DataGridView2.Rows(0).Cells(1).Value = Counts
For some reason, whatever in the first row of Grid1 is, it's always 1 lower than what it's supposed to be, so I add 1 to it in the end.
i got this problem on how to determine if the next row in a datagridview is equal to negative then current row will return a remarks.
For example;
Remarks Reference
A 1
A 2
B 3
-4
If the next row is a positive number, remarks will be A. And if the next row is a negative value, remarks will return B.
I'm struggling in this part.
Here is the code:
For Each r As DataGridViewRow In dgvSTSub.Rows
Bal = Bal + r.Cells(3).Value - r.Cells(1).Value
r.Cells(3).Value = Bal
If Bal > Bal + r.Cells(3).Value Then
r.Cells(2).Value = r.Cells(1).Value
End If
Next
That was not the actual datagridview as shown above but that is what i want to happen.
Any help/suggestion is appreciated.
From the given data. Remarks is in cells(0) and Reference is in cells(1)
To determine the negative integers from cells(1):
Assuming that References contains integers only: (use these codes)
Dim i As Integer = 0
Dim number As Integer
While i <= DataGridView1.RowCount - 1
number = CInt(DataGridView1.Rows(i).Cells(1).Value)
If number < 0 Then
MsgBox("Row: " & i & " is Negative number") ' Omit this line if you want.
' Add your codes here
End If
i += 1
End While
Is there any other way to sum all the items on the combo box
I'm trying to sum all the value on the combo box
this is my code:
For a As Integer = 0 To ComboBox1.Items.Count - 1
Dim b As Integer
b = ComboBox1.Items(a)
MetroLabel12.Text = ComboBox1.Items.Count(0) + b
Next b
The following code will take the string value of each item and try to convert it to integer. If successful, it will add the result to result.
Dim result as Integer = 0
Dim num as Integer = 0
For Each s As String In ComboBox1.Items
num = 0
If Integer.TryParse(s, num) Then
result = result + num;
End If
Next s
I'm trying to calculate how many layers a commodity will be stacked in. I have a variable quantity (iQty), a given width for the loadbed (dRTW), a width per unit for the commodity (dWidth) and a quantity per layer (iLayerQty).
The quantity per layer is calculated as iLayerQty = Int(dRTW/dWidth)
Now I need to divide the total quantity by the quantity per layer and round up. In an Excel formula it would be easy, but I'm trying to avoid WorksheetFunction calls to minimise A1/R1C1 confusion. At the moment I'm approximating it with this:
(Number of layers) = ((Int(iQty / iLayerQty) + 1)
And that works fine most of the time - except when the numbers give an integer (a cargo width of 0.5 m, for instance, fitting onto a 2.5 m rolltrailer). In those instances, of course, adding the one ruins the result.
Is there any handy way of tweaking that formula to get a better upward rounding?
I don't see any reason to avoid WorksheetFunction; I don't see any confusion here.
Number_of_layers = WorksheetFunction.RoundUp(iQty / iLayerQty, 0)
You could also roll your own function:
Function RoundUp(ByVal Value As Double)
If Int(Value) = Value Then
RoundUp = Value
Else
RoundUp = Int(Value) + 1
End If
End Function
Call it like this:
Number_of_layers = RoundUp(iQty / iLayerQty)
If using a WorksheetFunction object to access a ROUNDUP or CEILING function is off the table then the same can be accomplished with some maths.
Number of layers = Int(iQty / iLayerQty) - CBool(Int(iQty / iLayerQty) <> Round(iQty / iLayerQty, 14))
A VBA True is the equivalent of (-1) when used mathematically. The VBA Round is there to avoid 15 digit floating point errors.
I use -int(-x) to get the ceiling.
?-int(-1.1) ' get ceil(1.1)
2
?-int(1.1) ' get ceil(-1.1)
-1
?-int(-5) ' get ceil(5)
5
These are the functions I put together for this purpose.
Function RoundUp(ByVal value As Double) as Integer
Dim intVal As Integer
Dim delta As Double
intVal = CInt(value)
delta = intVal - value
If delta < 0 Then
RoundUp = intVal + 1
Else
RoundUp = intVal
End If
End Function
Function RoundDown(ByVal value As Double) as Integer
Dim intVal As Integer
Dim delta As Double
intVal = CInt(value)
delta = intVal - value
If delta <= 0 Then
RoundDown = intVal
ElseIf delta > 0 Then
RoundDown = intVal - 1
End If
End Function
This is my Ceiling in VBA.
Function Ceiling(ByVal Number As Double, ByVal Significance As Double) As Double
Dim intVal As Long
Dim delta As Double
Dim RoundValue As Double
Dim PreReturn As Double
If Significance = 0 Then
RoundValue = 1
Else
RoundValue = 1 / Significance
End If
Number = Number * RoundValue
intVal = CLng(Number)
delta = intVal - Number
If delta < 0 Then
PreReturn = intVal + 1
Else
PreReturn = intVal
End If
Ceiling = PreReturn / RoundValue
End Function