Setting string a variable to get values from a structured array - arrays

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.

Related

Search Multiple Text Files for Similar Data

I have multiple text files with similar data, for instance file1 would have the following entry:
test1, 1400
Then file2 would have:
test1, 2400
As all of these files are generated by different programs, is it possible to check through each text file for a similar entry, for instance using the files mentioned above, say I wanted to find test1 from both files and calculate the sum of the score and thus get the following data saved to another text file:
test1, 3800
The Programming Language I am using is VB.NET, currently I have read all of the files using:
Dim Array1() As String = IO.File.ReadAllLines("path")
My current logic is to get all of the data into a list or a KeyValuePair, where the list will store the username of the user as well with their score which would be summed at this point. I have currently read all of the data from each text file to an array, with each array in the FormLoad Event I have got it into a form where the data is split with a delimiter with the comma. At the start of the program I have an Input Box which asks the user for their Username and stores it in a variable called UserInput. From there this is what I need help achieving, I need the Program to get value from each array and store it in another array where it sorts the data of each user with their scores, from their I can use: For i = 0 to ar.length - 1 Loop to go through the array and search for the Users username.
You can use the following approach
Dim arr1 As New List(Of String)
arr1.AddRange(IO.File.ReadAllLines("text file 1"))
Dim arr2 As New List(Of String)
arr2.AddRange(IO.File.ReadAllLines("text file 2"))
Dim searchstring As String = "test1"
'You can replace test1 with the string you are searching the text file for
Dim index1 As Integer = 0
Dim index2 As Integer = 0
'Getting the index of the string in the list
'*******************************************
For x As Integer = 0 To arr1.Items.Count - 1
If arr1(x).StartsWith(searchstring) Then
index1 = x
End If
Next
For x As Integer = 0 To arr2.Items.Count - 1
If arr2(x).StartsWith(searchstring) Then
index2 = x
End If
Next
'*******************************************
Dim split1() As String = Split(arr1(index1), ",")
Dim split2() As String = Split(arr2(index2), ",")
Dim sum As Integer = Integer.Parse(Trim(split1(1))) + Integer.Parse(Trim(split2(1)))
'Writing the sum to another test file, the "output.txt" file would be created on your desktop, you can replace the path's string with your custom location
Dim path As String = Path.Combine(My.Computer.FileSystem.SpecialDirectories.Desktop, "output.txt")
Dim finaltext As String = searchstring + "," + sum.ToString
System.IO.File.AppendAllLines(path, finaltext)
The above method creates a new text file "output.txt" on your desktop.
AJD is correct. You need to make an attempt before posting. I answered because I want practice with Linq. Since you have 2 different types of data, a class or a structure is in order (or use a database). I filled a list of the structure by splitting the lines into the string portion and integer portion; setting the properties of the structure. You can add as many files as you wish to the List. I tested with both the Linq method and the Loop method.
Structure TestData
Public TestName As String
Public TestScore As Integer
End Structure
Private TestList As New List(Of TestData)
Private Sub AddToList(path As String)
Dim arr() As String = File.ReadAllLines(path)
For Each line As String In arr
Dim arr2() As String = line.Split(","c)
Dim td As TestData
td.TestName = arr2(0)
td.TestScore = CInt(arr2(1).Trim)
TestList.Add(td)
Next
End Sub
Private Function GetSummWithLinq(NameOfTest As String) As Integer
Dim result As Integer = (From Score In TestList
Where Score.TestName = NameOfTest
Select Score.TestScore).Sum
Return result
End Function
Private Function GetSumWithLoop(NameOfTest As String) As Integer
Dim total As Integer
For Each item In TestList
If item.TestName = NameOfTest Then
total += item.TestScore
End If
Next
Return total
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim p As String = "C:\Users\SomeUser\Desktop\TestData.txt"
AddToList(p)
Dim a As Integer = GetSummWithLinq("test1")
MessageBox.Show($"The Linq method produces {a}")
Dim b As Integer = GetSumWithLoop("test1")
MessageBox.Show($"The Loop method produces {b}")
End Sub
EDIT
My TestData.txt file that I used to test the code.
test1, 314
test2, 740
test1, 700
test2, 200

Adding Regex matches to an array

I'm struggling to solve a small bit of code. What the code does is to first load a CSV file, line by line (starting by line 3), and add it to an array. Then run a regex match and I want to insert the value in an array.
This is my working code, it shows a msgbox with the actual matches:
Dim file = "C:\Users\David\Desktop\mycsv.csv"
Dim basestatisticspath = Path.GetDirectoryName(file)
Dim statistics() As String = IO.File.ReadAllLines(file)
'Dim x As Integer = statistics.Length
'ReDim Preserve statistics(x)
Dim regexlang As Regex = New Regex("(?<=^"")\[.*\]")
Dim regexlinefilename As Regex = New Regex("(?<=^""\[.*?\]\s).*(?="")")
Dim linefilename As Match = Nothing
Dim langmatch As Match = Nothing
Dim filename() As String
Dim lang() As String
For i = 2 To UBound(statistics)
langmatch = regexlang.Match(statistics(i))
linefilename = regexlinefilename.Match(statistics(i))
MsgBox(langmatch.Value & linefilename.Value)
Next
That works well and the actual matches is what I want. So my next step was to add each match to an array to then use it to generate other files.
Therefore I ended up with this:
Dim file = "C:\Users\David\Desktop\myscv.csv"
Dim basestatisticspath = Path.GetDirectoryName(file)
Dim statistics() As String = IO.File.ReadAllLines(file)
'Dim x As Integer = statistics.Length
'ReDim Preserve statistics(x)
Dim regexlang As Regex = New Regex("(?<=^"")\[.*\]")
Dim regexlinefilename As Regex = New Regex("(?<=^""\[.*?\]\s).*(?="")")
Dim linefilename As Match = Nothing
Dim langmatch As Match = Nothing
Dim filename() As String
Dim lang() As String
' Set all value line by line
For i = 2 To UBound(statistics)
langmatch = regexlang.Match(statistics(i))
linefilename = regexlinefilename.Match(statistics(i))
lang(i) = langmatch.Value.ToString
filename(i) = linefilename.Value.ToString
MsgBox(langmatch.Value & linefilename.Value)
Next
After adding the below the program crashes on that line
lang(i) = langmatch.Value.ToString
filename(i) = linefilename.Value.ToString
I am assuming you can add the value of a regex match to a certain position of a string, but it seems I am wrong.
I´ve been searching for an answer with no results (at least to my poor understanding).
How could I convert each of the matches to a string and add it to the i position of the array?
Thanks in advance!
UPDATE:
As #Tval explained, I solved it by including the size of the array when declaring it. Thanks!
Dim filename(UBound(statistics)) As String
Dim lang(UBound(statistics)) As String
you need to initialize the array before you can reference it or you'll get a null reference error, also you can't reference an index that doesn't exist yet or you'll get an index out of range exception.
right now your using an array with a fixed length, so if you want to add a value to it you'll have to re-declare it one index larger every time.
If you want an array of a variable length id suggest using a list, so you can just append values to it without any issues
Dim myList = New List(Of String)
For Each foo As String In bar
myList.Add(bar)
Next

Function caller code VBA

Problem
When you want to look directly at the arguments of your UDF (not their values, which can be passed directly, but the formula that gave these values), you can use Application.Caller.Formula and parse out the arguments to find out.
Is there any way to see the line of VBA code which called a Function, so that you can parse out its arguments in a similar way?
Background
A while ago I created a UDF which was essentially another approach to array functions*. What I wanted to do was take some statement which evaluates to True/False
LEN(A1)>LEN(B1)
And evaluate it over an array. So say the above function was placed in cell A1, then to evaluate over the array A1:A100 would be the same as creating the array
{LEN(A1)>LEN(B1),LEN(A2)>LEN(B2),[...]} 'you may recognise this as an array formula ={LEN(A1:A100)>LEN(B1:B100)}
*For context, this was before I knew about array formulae
I was frustrated with the syntax of certain array-handling Excel functions, like COUNTIF, which takes the arguments in the following form
COUNTIF(range_To_Evalueate_Over, "string_Representing_Boolean_Test")
The string argument presents the following limitations
Not any boolean returning statement can be used as a test; there is no way of looking at properties of the range which you evaluate over other than their values
So you can't use functions like LEN() to get more data about the range
You can not reference other cells relative to the range (Like B1 relative to A1)
The string is static at runtime, you cannot step-into the function to see what the string will evaluate to for a given cell from the range you are evaluating
I much prefer the versatility of the conditional formatting formulae. They take the form of array formulae, where any offsets (B1 relative to A1) are calculated relative to the TL cell of the range that the conditional formatting is applied to.
That prompted me to create a UDF which has a structure like this
evaluateOverRange(range_to_evalute_over As Range, boolean_test_on_TL_Cell As Boolean) As Boolean() 'returns an array equal in size to the evaluate range
Used like
evaluateOverRange(A1:A100,LEN(A1)<LEN(B1))
Note
Boolean test is not a string, so can be evaluated step by step in Excel
Boolean test is guaranteed to be Boolean thanks to type declaration
Boolean test is relative to the first cell (A1) in the evaluate range (A1:A100)
I.e. B1 is replaced with A1.Offset(0,1)
Since boolean_test_on_TL_Cell is not a string, it tells us nothing about the actual test, it just passes the result of the test on the A1, it is actually useless within the UDF so is ignored
To obtain the test string "LEN(A1)<LEN(B1)", the Application.Caller.Formula is read, and the relevant argument of evaluateOverRange is parsed out
In order to evaluate some worksheet function over an array in VBA, you can use the Evaluate method
Dim colA As Range: Set colA = [A1:A100] 'range_to_evaluate_over in my udf
Dim cellA As Range
Dim cellB as Range
Dim outputArray(1 To 100) As Boolean
For i = 1 To 100
Set cellA = colA(i)
Set cellB = cellA.Offset(0,1) 'all cells that arent the TL cell in colA (i.e., not A1) are set relative to the top left cell
outputArray(i) = Evaluate("LEN(" & cellA.Value & ")>LEN(" & cellB.Value ")")
Next i
Right, so all that was for worksheet functions, and somewhat pointless given array functions do the same thing. But now I want to use the same approach within VBA.
Specifically, I want to filter an array of custom classes based on some function of their properties, using actual VBA Boolean returning code rather than a string.
Sub FilterMyClassArray() 'Prints how many items in arrayToFilter whose properties match certain conditions
Dim arrayToFilter(1 To 100) As New myClass
Dim filteredArray() As myClass
Dim tlClass As myClass 'pretend class used only for intellisense and to create
boolean test
Set filteredArray = filterClassArray(arrayToFilter, tlClass.PropertyA > 3 And
tlClass.PropertyB = "hat")
Debug.Print "Number left after filtering:" ; Ubound(filteredArray)
End Sub
Function filterClassArray(ByVal inutArray() As myClass, classTest As Boolean) As myClass 'returns an output array which is equal to the input array filtered by some test
'Somehow get what classTest actually was
'Evaluate classTest over each item in inputArray
'If boolean test evaluates to true, add to output array, otherwise skip
End Function
I imagine some manipulation of the code modules will be required (both to get the string of code which represents the test, and to actually evaluate it), but I want to check feasibility before I dig too deep.
I've been having a think about this and a solution might be possible if you'd be prepared to use something approximating a Linq syntax.
If I understand the requirements correctly, you need to:
obtain a string value for each property name,
record the evaluation and ultimately run it as a string,
have intellisense access to the properties, and
have the ability to debug the evaluation on each iteration.
Regarding #1 and #3, the only way of doing this in VBA would be to code the values manually. If you code them in your class then the class can become cumbersome and some might say it compromises the single responsibility principle (https://en.wikipedia.org/wiki/Single_responsibility_principle). If you code them in a separate 'container' (eg class, type, collection, etc.), then there's a risk of some being missed or of corruption if you change the property names. An Interface class might mitigate these issues.
For #2, I can't see any way around it: the evaluation must be entered as a string. An enum (and associated intellisense) might alleviate things a bit though.
Item #4 is purely a coding architecture issue.
First the syntax
I'm sure there are VBA solutions on the internet which implement a pretty decent mock-up of Linq, but further down is a skeleton version to give you the idea. The end result is that your query syntax could look like this:
Dim query As cLinq
Dim p As INameable
Dim arrayToFilter(1 To 100) As INameable
Dim filteredArray() As INameable
Set query = New cLinq
With query
.SELECT_USING_INTERFACE p
.FROM arrayToFilter
.WHERE p.PropertyA, EQUAL_TO, 3
.AND_WHERE p.PropertyB, EQUAL_TO, "hat"
filteredArray = .EXECUTE
End With
The interface
As far as VBA is concerned an interface is really just a class module with a list of properties and methods that you want a class to implement. In your case, I've created a class and called it INameable, with the following sample code to match your example:
Option Explicit
Public Property Get PropertyA() As Long
End Property
Public Property Let PropertyA(RHS As Long)
End Property
Public Property Get PropertyB() As String
End Property
Public Property Let PropertyB(RHS As String)
End Property
Your MyClass class then implements this interface. For the sake of consistency, I've called the class cMyClass:
Option Explicit
Implements INameable
Private mA As Long
Private mB As String
Private Property Let INameable_PropertyA(RHS As Long)
mA = RHS
End Property
Private Property Get INameable_PropertyA() As Long
INameable_PropertyA = mA
End Property
Private Property Let INameable_PropertyB(RHS As String)
mB = RHS
End Property
Private Property Get INameable_PropertyB() As String
INameable_PropertyB = mB
End Property
I've created a second class, called cNames, which also implements the interface, and this one produces the string names of the properties. As a quick and dirty method it just stores the name of the last property used:
Option Explicit
Implements INameable
Private mName As String
Private Property Let INameable_PropertyA(RHS As Long)
End Property
Private Property Get INameable_PropertyA() As Long
mName = "PropertyA"
End Property
Private Property Let INameable_PropertyB(RHS As String)
End Property
Private Property Get INameable_PropertyB() As String
mName = "PropertyB"
End Property
Public Property Get CurrentName() As String
CurrentName = mName
End Property
You wouldn't have to use an interface and some might argue it's not necessary or even correct to do so, but at least it gives you an idea of how it could be implemented if you went this route.
The Linq class
The final class is really just a helper class to create the intellisense syntax you need and to process the evaluation. It's by no means thorough, but might get you started if the idea appealed to you. I've called this class cLinq:
Option Explicit
'Enumerator to help with intellisense.
Public Enum Operator
EQUAL_TO
GREATER_THAN
LESS_THAN
GREATER_OR_EQUAL_TO
LESS_OR_EQUAL_TO
NOT_EQUAL_TO
End Enum
Private mP As cNames
Private mQueries As Collection
Private mByAnd As Boolean
Private mFromArray As Variant
Public Sub SELECT_USING_INTERFACE(p As INameable)
'Insantiate the name of properties class.
Set mP = New cNames
Set p = mP
End Sub
Public Sub FROM(val As Variant)
'Array containing objects to be interrogated.
mFromArray = val
End Sub
Public Sub WHERE(p As Variant, opr As Operator, val As Variant)
'First query.
Set mQueries = New Collection
AddQuery opr, val
End Sub
Public Sub AND_WHERE(p As Variant, opr As Operator, val As Variant)
'Subsequent query using AND.
mByAnd = True
AddQuery opr, val
End Sub
Public Sub OR_WHERE(p As Variant, opr As Operator, val As Variant)
'Subsequent query using OR.
mByAnd = False
AddQuery opr, val
End Sub
Public Function EXECUTE() As Variant
Dim o As Object
Dim i As Long
Dim result As Boolean
Dim matches As Collection
Dim output() As Object
'Iterate the array of objects to be checked.
Set matches = New Collection
For i = LBound(mFromArray) To UBound(mFromArray)
Set o = mFromArray(i)
result = EvaluatedQueries(o)
If result Then matches.Add o
Next
'Transfer matched objects to an array.
ReDim output(0 To matches.Count - 1)
i = LBound(output)
For Each o In matches
Set output(i) = o
i = i + 1
Next
EXECUTE = output
End Function
Private Function EvaluatedQueries(o As Object) As Boolean
Dim pep As Variant, val As Variant
Dim evalString As String
Dim result As Boolean
For Each pep In mQueries
'Obtain the property value by its string name
val = CallByName(o, pep(0), VbGet)
'Build the evaluation string.
evalString = ValToString(val) & pep(1)
'Run the evaluation
result = Evaluate(evalString)
'Exit the loop if AND or OR conditions are met.
If mQueries.Count > 1 Then
If (mByAnd And Not result) Or (Not mByAnd And result) Then Exit For
End If
Next
EvaluatedQueries = result
End Function
Private Sub AddQuery(opr As Operator, val As Variant)
Dim pep(1) As Variant
'Create a property/evaluation pair and add to collection,
'eg pep(0): "PropertyA", pep(1): " = 3"
pep(0) = mP.CurrentName
pep(1) = OprToString(opr) & ValToString(val)
mQueries.Add pep
End Sub
Private Function OprToString(opr As Operator) As String
'Convert enum values to string operators
Select Case opr
Case EQUAL_TO
OprToString = " = "
Case GREATER_THAN
OprToString = " > "
Case LESS_THAN
OprToString = " < "
Case GREATER_OR_EQUAL_TO
OprToString = " >= "
Case LESS_OR_EQUAL_TO
OprToString = " <= "
Case NOT_EQUAL_TO
OprToString = " <> "
End Select
End Function
Private Function ValToString(val As Variant) As String
Dim result As String
'Add inverted commas if it's a string.
If VarType(val) = vbString Then
result = """" & val & """"
Else
result = CStr(val)
End If
ValToString = result
End Function

Let and Get array of fixed size

I have a class that has a fixed-size array of Double, for example
Private m_values(8) as Double
What is the correct syntax for the Let and Get methods for an array?
Public Property Let Values (RHS(8) as Double)
m_values = RHS
End Property
Public Property Get Values() as Double
Values = m_values
End Property
The specific parts of the syntax I am unclear about:
a. In the Let method, is RHS(8) as Double the correct way to pass an array of 8 Double?
b. Can I copy one array to another simply using assignment? (e.g. m_values = values)
c. For the Get method, is it correct for the function to be declared as Double or should it be something like as Double(8)?
The only way to declare a property that can hold arrays is as Variant property.
Private m_values As Variant
Public Property Let Values(RHS As Variant)
m_values = RHS
End Property
Public Property Get Values() As Variant
Values = m_values
End Property
Public Sub Test()
Dim x(8) As Double
x(1) = 123.55
x(2) = 456.45
x(5) = 789.66
x(8) = 123.777
' assign value to property
Values = x
' get value from property
Dim y() As Double
y = Values
Dim i As Integer
For i = 0 To UBound(y)
Debug.Print y(i)
Next
End Sub
Try to keep the following rules:
'starting point- array with 8 elements
Dim arrStart(8) As Double
arrStart(8) = 1 'here- for testing with Local window
'passing array to another...Variant type variable
'no array declaration required
Dim arrVariant As Variant
arrVariant = arrStart
'passing array to another Double variable
'dynamic array declaration required
Dim arrEmpty() As Double
arrEmpty = arrStart
These rules work also when passing variable (as an parameter) to another property, function or subroutine. This also means that you can't declare Get Property as an array and you should declare it as a Variant type.

Assigning Range array from a returning function

I want to have an array of ranges to create charts from them.
Here's how I had it:
Dim infoR As Range
Dim aRng() As Range
Dim numLvls As Integer
Set infoR = Range("H1:H100");
numLvls = getLevels()
Set aRng() = getOnlyNumericCellToArrayRanges(infoR, numLvls)
The function is this:
Function getOnlyNumericCellsRangesArrays(ByVal actRange As Range, ByVal numLvls As Integer) As Range()
Dim aRng() As Range
Redim aRng(0 To numLvls - 1)
'Some code
Set getOnlyNumericCellToArrayRanges = aRng()
End Function
I've seen several arrays examples over the internet and they use variant as a data type for that means but it doesn't compile like that too.
I've found that works with some changes:
Dim aRng
'Some code
aRng = getOnlyNumericCellToArrayRanges(infoR)
I think passing the array by reference could work, however I want to know if there is a way to make the array declaration and assignment to Range data type explicitly from the beginning.
Or how can I cast the result array back into a Range array?
An array is not an object (even when it's an array of objects), so you don't need Set here...
Sub Tester()
Dim arrRng() As Range, x As Long
arrRng = GetRangeArray()
For x = LBound(arrRng) To UBound(arrRng)
Debug.Print arrRng(x).Address()
Next x
End Sub
Function GetRangeArray() As Range()
Dim arrRng() As Range
ReDim arrRng(1 To 3)
Set arrRng(1) = ActiveSheet.Range("A1")
Set arrRng(2) = ActiveSheet.Range("A3")
Set arrRng(3) = ActiveSheet.Range("A5")
GetRangeArray = arrRng
End Function

Resources