I have a simple problem in VB.net. I want to retrieve datas from an array declared as structure using a string to visualize the variable. Below my code:
Module DataAnalisys
Dim InputData(100000) As InputDataStructure
Dim VariablesParameter(6) As VariablesParameterStructure
Dim VariablesGlobal(6) As VariablesDataStrucutre
Structure InputDataStructure
Dim ID As Integer
Dim FileId As Integer
Dim ProductionDate As Date
Dim ProductionTime As Date
Dim Shift As Integer
Dim IPP As Integer
Dim BPS As Integer
Dim SerialNumber As String
Dim Top As Single
Dim Bottom As Single
Dim Right As Single
Dim Left As Single
Dim OffCutH As Single
Dim OffCutV As Single
Dim Row As Byte
Dim Col As String
Dim Position As String
Dim Pack As Integer
Dim Sheet As Integer
Dim SheetInPack As Integer
End Structure
Structure VariablesParameterStructure
Dim NameParameter As String
Dim Target As Single
Dim Tolerance As Single
Dim LowTolerance As Single
Dim UppTolerance As Single
End Structure
Structure VariablesDataStrucutre
Dim NameData As String
Dim Position As String
Dim N As Long
Dim Mean As Single
Dim Difference As Single
Dim Scrap As Single
Dim ScrapGreat As Single
Dim ScrapLess As Single
Dim SeMean As Single
Dim StDev As Single
Dim Min As Single
Dim Q1 As Single
Dim Median As Single
Dim Q3 As Single
Dim Max As Single
End Structure
Sub RoutineAnalisysGlobal()
For B As Byte = 0 To VariablesGlobal.Length - 1
Dim ID As String = VariablesParameter(B).NameParameter
Dim Target As Single = VariablesParameter(B).Target
Dim LowTol As Single = VariablesParameter(B).LowTolerance
Dim UppTol As Single = VariablesParameter(B).UppTolerance
With VariablesGlobal(B)
.NameData = ID
.Position = "All"
.N = InputData.Length
.Mean = InputData.Average(Function(f) f.ID)
.Difference = .Mean - Target
.ScrapLess = InputData.Count(Function(f) f.ID < LowTol)
.ScrapGreat = InputData.Count(Function(f) f.ID > UppTol)
.Q1 = InputData.FirstQuartile(Function(F) F.ID)
.Min = InputData.Min(Function(f) f.ID)
.Median = InputdataMedian(Function(f) f.ID)
.Q3 = InputData.ThirdQuartile(Function(f) f.ID)
.Max = InputData.Max(Function(f) f.ID)
End With
Next
End Sub
End Module
The VariablesParameter().Name are Top, Bottom, Right, Left, OffCutH and OffCutV.
The code does not work when I'm using the part (Function(f) f.ID) as I want to use the function on different items of the structure of InputData according the for cycle. I want to display f.Top f.Bottom f.Right f.Left f.OffCutH and f.OffCutV.
Does anyone want to help me? I was looking on how convert the string ID into the variable of InputData.?????? structure.
I think what you're looking for is something like this:
Dim functions As Func(Of InputDataStructure, Single)() = {Function(ids) ids.Top,
Function(ids) ids.Bottom,
Function(ids) ids.Right,
Function(ids) ids.Left,
Function(ids) ids.OffCutH,
Function(ids) ids.OffCutV}
For i = 0 To VariablesGlobal.GetUpperBound(0)
With VariablesGlobal(i)
'...
.Mean = InputData.Average(functions(i))
'...
End With
Next
By way of explanation, the Function(f) f.ID
part of this line:
.Mean = InputData.Average(Function(f) f.ID)
is a lambda expression, i.e. a delegate for an anonymous method. The Average
method that you're calling requires a delegate for a method that has a single argument of type T
, where T
matches the generic type of the IEnumerable(Of T)
that you're calling it on, and returns a value of a numeric type, e.g. Integer
or Single
. In your case, you are calling Average
on InputData
, which implements IEnumerable(Of InputDataStructure)
. Your lambda expression has a parameter of type InputDataStructure
and returns an Integer
, so it works with Average
. The Average
method invokes that delegate for every item in the list, gets all the numeric results and then divides that by the number of items in the list to get the average.
To make it clearer what is happening there, you could used a named method instead of a lambda expression. You could write this method:
Private Function GetID(f As InputDataStructure) As Integer
Return f.ID
End Function
and then change your code to this:
.Mean = InputData.Average(AddressOf GetID)
Hopefully you can identify the parts of that named method that correspond to the lambda express and the parts that are inferred.
Now, you have a number of lines of code there that use the same lambda expression, e.g.
.Min = InputData.Min(Function(f) f.ID)
.Median = InputdataMedian(Function(f) f.ID)
.Q3 = InputData.ThirdQuartile(Function(f) f.ID)
for something so simple, it is customary to do it the way you have. You do have the option, though, of writing the lambda expression once, assigning it to a variable and then using that variable multiple times. You could do this:
Dim f As Func(Of InputDataStructure, Integer) = Function(ids) ids.ID
or this:
Dim f = Function(ids As InputDataStructure) ids.ID
to end up with the variable f
referring to a delegate that takes an argument of type InputDataStructure
and returns a value of type Integer
. You can then use that variable where you previously used multiple lambda expressions:
.Min = InputData.Min(f)
.Median = InputdataMedian(f)
.Q3 = InputData.ThirdQuartile(f)
So, now that we determined that all you need is a delegate to a method that takes an argument of the correct type and returns the correct type, take another look at the code I posted. It first creates an array of six delegates, each of which takes an argument of type InputDataStructure
and returns a value of type Single
. You can then use an element of that array wherever such a delegate is expect.
That means that you can loop over that array and pass each delegate to all the extensions methods that expect such a delegate, including Average
. If you get the delegate at index 0 then you get the delegate that returns the Top
property value, so Average
will get the average Top
value. If you use index 5 then you get the delegate that returns the OffCutV
property value, so Average
will get the average OffCutV
value. Etc.
For the record, I recommend using parameter names in lambdas that indicate the type. You used f
but that's meaningless. The parameter type is InputDataStructure
so ids
is indicative of that.