#arrays #vb.net #structure
Вопрос:
У меня есть простая проблема в VB.net. Я хочу извлечь данные из массива, объявленного как структура, используя строку для визуализации переменной. Ниже моего кода:
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
Переменные Parameter().Имя: Верхний, Нижний, Правый, Левый, OffCutH и OffCutV.
Код не работает, когда я использую часть (функцию(f) f.ID) так как я хочу использовать функцию для разных элементов структуры входных данных в соответствии с циклом for. Я хочу отобразить f.Сверху f.Снизу f.Справа f.Слева f.OffCutH и f.OffCutV.
Кто-нибудь хочет мне помочь? Я смотрел, как преобразовать идентификатор строки в переменную inputData.?????? структура.
Комментарии:
1. Что именно это должно делать:
.Mean = InputData.Average(Function(f) f.ID)
? В нынешнем виде вы получаете среднее значение всехID
значений, что, похоже, не имеет смысла. Я подозреваю, что на самом деле вы хотите получить среднее значение какого-либо другого поля для всех элементов, гдеID
оно равно некоторому определенному значению. Это правильно? Если это так, то вам нужно сначала позвонитьWhere
, чтобы отфильтровать данные, затем позвонитьAverage
и указать поле, в котором вы хотите получить среднее значение, например.Mean = InputData.Where(Function(f) f.ID = ID).Average(Function(f) f.Top)
.2. @jmcilhinney, возможно, идентификатор вводит в заблуждение, поскольку он присутствует в коде два раза. Я хочу сделать действительно простую вещь, например, просто следующие 6 средних значений:
InputData.Average(Function(f) f.Top) - InputData.Average(Function(f) f.Bottom) - InputData.Average(Function(f) f.Right) - InputData.Average(Function(f) f.Left) - InputData.Average(Function(f) f.OffCutHTop) - InputData.Average(Function(f) f.OffCutV)
но я не знаю, как перейти в цикл for междуf.Top, f.Bottom, f.Right, f.Left, f.OffCutH and f.OffCutV
3. Похоже, вам нужны массивы с 6 элементами, учитывая, что вы говорите об усреднении 6 полей. Если это так, то способ , которым вы создаете свои массивы, например
Dim VariablesParameter(6) As VariablesParameterStructure
, неверен. Это создает массив из 7 элементов. Вы указываете верхнюю границу при создании массива в VB, которая на 1 меньше длины.4. У вас также есть некоторые орфографические ошибки в коде. У вас есть «Анализ» вместо «Анализ» в двух местах и «Структура» вместо «Структура» в одном месте. Вы также должны иметь
Option Strict Off
для этого код для компиляции, что плохо. Почему вы думаете, что использование aByte
вFor
цикле для индексирования массивов было хорошей идеей? Индексы ЕСТЬ ВСЕГДАIntegers
. ВключитеOption Strict On
этот проект и сделайте его по умолчанию в параметрах VS для всех проектов и помогите себе перестать писать плохой код.
Ответ №1:
Я думаю, что вы ищете что-то вроде этого:
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
В качестве объяснения, Function(f) f.ID
часть этой строки:
.Mean = InputData.Average(Function(f) f.ID)
является лямбда-выражением, т. е. делегатом для анонимного метода. Average
Метод , который вы вызываете, требует делегата для метода, имеющего один аргумент типа T
, который T
соответствует универсальному типу IEnumerable(Of T)
, для которого вы его вызываете, и возвращает значение числового типа, например Integer
или Single
. В вашем случае вы Average
призываете InputData
, что реализует IEnumerable(Of InputDataStructure)
. Ваше лямбда-выражение имеет параметр типа InputDataStructure
и возвращает значение an Integer
, поэтому оно работает с Average
. Average
Метод вызывает этот делегат для каждого элемента в списке, получает все числовые результаты, а затем делит их на количество элементов в списке, чтобы получить среднее значение.
Чтобы было понятнее, что там происходит, вы могли бы использовать именованный метод вместо лямбда-выражения. Вы могли бы написать этот метод:
Private Function GetID(f As InputDataStructure) As Integer
Return f.ID
End Function
а затем измените свой код на этот:
.Mean = InputData.Average(AddressOf GetID)
Надеюсь, вы сможете определить части этого именованного метода, которые соответствуют лямбда-выражению, и части, которые выводятся.
Теперь у вас есть несколько строк кода, в которых используется одно и то же лямбда-выражение, например
.Min = InputData.Min(Function(f) f.ID)
.Median = InputdataMedian(Function(f) f.ID)
.Q3 = InputData.ThirdQuartile(Function(f) f.ID)
для чего-то столь простого принято делать это так, как у вас есть. Однако у вас есть возможность написать лямбда-выражение один раз, присвоить его переменной, а затем использовать эту переменную несколько раз. Ты мог бы сделать это:
Dim f As Func(Of InputDataStructure, Integer) = Function(ids) ids.ID
или это:
Dim f = Function(ids As InputDataStructure) ids.ID
чтобы в конечном итоге переменная f
ссылалась на делегат, который принимает аргумент типа InputDataStructure
и возвращает значение типа Integer
. Затем вы можете использовать ту переменную, в которой ранее использовали несколько лямбда-выражений:
.Min = InputData.Min(f)
.Median = InputdataMedian(f)
.Q3 = InputData.ThirdQuartile(f)
Итак, теперь, когда мы определили, что все, что вам нужно, — это делегат метода, который принимает аргумент правильного типа и возвращает правильный тип, еще раз взгляните на код, который я опубликовал. Сначала он создает массив из шести делегатов, каждый из которых принимает аргумент типа InputDataStructure
и возвращает значение типа Single
. Затем вы можете использовать элемент этого массива везде, где ожидается такой делегат.
Это означает, что вы можете перебирать этот массив и передавать каждый делегат всем методам расширений, которые ожидают такого делегата, в том числе Average
. Если вы получите делегата с индексом 0, то вы получите делегата, который возвращает значение Top
свойства, поэтому Average
получите среднее Top
значение. Если вы используете индекс 5, то вы получите делегат, который возвращает значение OffCutV
свойства, поэтому Average
получите среднее OffCutV
значение. И т.д.
Для записи я рекомендую использовать имена параметров в лямбдах, которые указывают тип. Ты использовал f
, но это бессмысленно. Тип параметра InputDataStructure
so ids
указывает на это.