Calling a variable by a variable excel - excel

I wondering how I can use a variable to call another variable. For example Apple1, Apple2, Apple3, Apple4, Apple5, Apple6 and AppleNum.
Let us say AppleNum is 4. How can I use AppleNum to call for the code to use Apple4?
Also, What if Apple1, Apple2...ect are objects?
My first thought on how to solve this was by using some sort of Array?
Note: Using Select Case here will work but doesn't simply the code I have and would require each case to be written out individually (a lot of work)
Just out of interest, ts there a way to define AppleNum number of variables in the code?
If you can help, Thanks!

It is possible to have an array of variable size in VBA, using the following (for example):
Dim myArray() as Double
Dim AppleNum as Integer, arraySize as Integer
AppleNum = 4
arraySize = 6
ReDim myArray(1 to arraySize)
this would create an array myArray, and change its size to be 6 elements long (with index starting at 1). You can declare the entire array in one statement (without redimensioning) with
myArray = Array(Apple1, Apple2, Apple3, Apple4, Apple5, Apple6)
Assuming that Apple1 etc. have been previously declared.
If you declare myArray as Variant rather than Integer (or don't give a type - defaults to Variant) then your array can contain anything you want.
You can also use
ReDim Preserve myArray(1 to arraySize * 2)
if at a later point you want the array to be twice as large, but you don't want to lose the first six elements you had assigned.
I hope these things will get you moving with your problem.

Related

Type mismatch (Error 13) when assigning Split Variant/String to Variant/Variant() Array

Why do I get a Type Mismatch error on the last line?
Dim LineArray()
Dim Line
Dim FilePath as String
FilePath = "X:\Path\To\File.txt"
Open FilePath For Input As #1
Line Input #1, Line
Close #1
LineArray = Split(Line, vbTab)
LineArray is a Variant/Variant()
Line is a Variant/String
If I Dim them both as Variants I still get the error
As written in the comments: Split returns an array of Strings.
So the correct syntax is
Dim LineArray() As String
LineArray = Split(Line, vbTab)
The VBA compiler knows that LineArray will be an array of Strings. However, as it is declared as dynamic array, it is not an array before you assign members to it. Usually, this is done using the ReDim-statement that reserves the necessary space for a certain number of variables of a specific type. When using the split-function, this ReDim (or something similar) is done inside the function.
Now Variant is a very special data type - it can hold any type of data. This can be an Integer, a String, a Date, an Object (reference), an Error, or the value Empty (which means nothing is assigned yet). And, it can even be an array of any datatype. You can get the information about what data it contains using the function VarType().
What you can`t do is assign the result to an static array:
Dim LineArray(0 to 3) As String
LineArray = Split(Line, vbTab)
This will throw a compile error: Can't assign to array. The variable is not only defined, the memory is already reserved (in this case 4 Strings).
What you also can't do is to assign the result to an array of Variant. Why? Because the Split creates an Array of Strings. Now if you would assign this to an array of Variant, it would be possible to assign, let's say, a Double to the first element. However, the memory was reserved by Split to hold an String, so horrible things would happen to the memory.
Dim LineArray(0) As Variant
LineArray = Split(Line, vbTab)
LineArray(0) = 3.1415926 ' Ouch!
What would be needed is an instance that
Reserve memory for n Variant variables and assign it to LineArray (n = number of strings returns by Split)
Loop over all elements of the string array and assign the strings one by one to the variant array.
Now while this is possible, no instance will do this for you. The Split-function creates and returns the String array. The assignment operator ("=") is capable to assign any value to a Variant, but is not capable to reserve an array and copy elements one by one.

As String vs As String() in VBA [duplicate]

This may sound trivial, but what is the difference between
Dim v As String()
and
Dim v() As String
in VB.NET?
No difference. From the VB.NET Language Specification on Arrays:
Array types are specified by adding a modifier to an existing type name. The modifier consists of a left parenthesis, a set of zero or more commas, and a right parenthesis.
...
A variable may also be declared to be of an array type by putting an array type modifier or an array initialization modifier on the variable name. In that case, the array element type is the type given in the declaration, and the array dimensions are determined by the variable name modifier. For clarity, it is not valid to have an array type modifier on both a variable name and a type name in the same declaration.
Originally, in Basic, you had to define arrays, but not variables. And the types of variables were defined by a suffix character: A$ was a string, while A% was an integer and A# was double precision. (and all three were distinct and could be used at the same time) (For single-precision, you could use A!, but that was the default if you just used A)
Eventually, programmers came to realize that those were incredibly bad design choices.
To rectify this, Microsoft added "Option Explicit" which required you to predefine every variable. To lessen the effect on the language, they hijack the "DIM" command, which was used to define arrays, to define scalar variables as well.
So originally:
DIM A(50) ' define 51-element single-precision array
Then
DIM A(50) ' define 51-element single-precision array
DIM A$ ' define a string
Then to get rid of the suffixes, they added the "As {type} syntax"
DIM A(50) ' define 51-element single-precision array
DIM B as String
DIM C(50) as String ' define 51-element string array.
Then they made array size variable.
DIM A() ' define single-precision array
DIM B as String
DIM C() as String ' define string array.
This left a conflict in definition style, so they allowed both:
DIM A() ' define single-precision array
DIM B as String
DIM C() as String ' define string array.
DIM D as String() ' define string array.
There is no difference.
Both Dim v As String() and Dim v() As String will create a string array
Traditionally, in Basic, you would put the parenthesis after the variable name. In VB.Net it is allowed to put them after the type instead if you wish. The result is the same so there is no difference using either syntax. The reason for this addition though is because how you can constuct an array. Consider the following code:
Public Sub MethodThatExpectsAnArray(ByVal arr() As String)
'...
End Sub
Public Sub Main()
Me.MethodThatExpectsAnArray(New String() {"Hello", "World"})
End Sub
In the call I construct the array "on the fly" without any assignment except directly to the method argument. Since there are no variable here I must set the paranthesis after the type. To allow this syntax Microsoft had the choice to either change how you traditionally declare arrays in Basic or allow for both syntaxes. They of course opted for the latter.
There is no difference.
It's mostly semantics. The first reads as create variable "v" of type string array and the 2nd reads as create array "v" of type string. Either way the result is the same array of strings.
There is no difference in the meaning of the two.
If you like to declare several variables in one dim statement, the second form provides more flexibility:
dim v(),v2 as string allows you to declare array types and non array types in the same statement.

Pass ListObject to array. type variable String error

The idea is passing the complete content of a listobject.databodyrange to an array to make operations in memory and not having to access the sheets cells values repeatedly which is very time consuming.
this is the code.
Dim theArray As Variant
theArray = mylistObject.DataBodyRange.value
MsgBox (theArray(1, 1)) '= column 1 row 1 = first element
It works, so far so good.
but!!! since theArray is dimensioned as Variant, their elements are NOT strings, So when passing every of the values of theArray into a function that requires a string an error appears.
what to do?
Note: I know I might change the data type of the function itself to variant, but this function is called from so many routines that i dont dare to touch it. I rather prefer try to look for the way to transform the content of that variant into a string
like theArray(i,j) to str(thearray(i,j)) (which does not work)
some help, some ideas?
EDIT 1:
this is the line of the error:
Dim theclaims As Variant
theclaims = rawClsTbl.DataBodyRange.value
For i = LBound(theclaims, 1) To UBound(theclaims, 1)
myText = deleteRefSigns(theclaims(i, 2))
etc
error: byref argument type missmatch
where:
Function deleteRefSigns(txT As String) As String
i will be trying the solutions proposed.
thx
Related questions:
I asked in overflow myself this question some time ago:
Passing Listobject Range to array and getting error "out of range"
and read also this one
Excel VBA Type Mismatch Error passing range to array
and several others.
The following should work:
Dim MyStr As String
MyStr = CStr(TheArray(1, 1))
Note: Always declare it as a forced array not just as Variant …
Dim TheArray() As Variant 'Variant array (can only be an array)
Dim TheArray As Variant 'Variant (can be a value or array)
… to ensure it contains an array. Otherwise it will contain only a value if you do
TheArray = Range("A1").Value
which might easily fail if your range is dynamic.
If you read a range into an array like
Dim TheArray() As Variant
TheArray = Range("A1:C20").Value
then there is no possibility to declare the array as String it is forced to be Variant by design.
It looks like you don't want deleteRefSigns to modify the argument passed by the calling procedure. If so, you can pass the argument by value...
Function deleteRefSigns(ByVal txT As String) As String

Why does my code run without 'Option Explicit' but fail with it?

I am constructing my first major program in VBA (With some help from SO). The beginning of it is below, and I am adding blocks of code in as structured a way as possible. Having read about the importance of using 'Option Explicit' though, I inserted it and started to declare all my variables. Running the program gave - 'Compile Error: Variable not Defined'.
I have tried deleting and re-entering declarations in case the problem was caused by me adding 'Option Explicit' after starting on the code, as well as removing the UDF and adding that back in, but without success.
Commenting out 'Option Explicit' does away with the error message and the subsequent blocks of code run exactly as designed.
EDIT:I should have said that the error always occurs with 'iLoopControl'.
Option Explicit
'UDF to roll a number of Dice of specified size and total them
Function Dice(NoOfDice, DiceSize)
Dice = 0
For iLoopControl = 1 To NoOfDice
Dice = Dice + WorksheetFunction.RandBetween(1, DiceSize)
Next
End Function
Sub MercOne()
Randomize
Dim Merc(86)
Dim Temp As Integer, TechLevel As Byte, ArmOfService As Byte
Dim Year As Byte, YearCount As Byte
Dim GenAssignment As Variant, UnitAssignment As Variant
Dim SpecAssignmentSwitchEnd As Byte, Roll As Byte
Dim Rank As Variant, NoOfDice As Variant, DiceSize As Byte
Dim GenAssignmentSwitchInt As Byte, GenAssignmentSwitchOff As Byte
Dim CharacterNumber As Long, iLoopControl As Long
I applaud you for using Option Explicit! Now you have to learn to use it well...
You have to declare a variable before using it. You use iLoopControl in your function Dice before declaring it. VBA will assume (absent Option Explicit) that you were just lazy, and create a Variant variable for you. But if you misspelled the variable name, it would create a new one - and debugging would be really difficult because you won't understand why values are wrong...
As an aside, it is a good idea to avoid Variant in general, except when you know the variable can contain different types, when you will use it in a For Each loop, or when it is an optional parameter in a function. It is slower than a "regularly typed" variable and takes more space. In larger programs that can make a difference. And if you do want a Variant, you don't need to say As Variant since that is implied.
One more point about your code: you declare iLoopControl in the scope of a Sub. That means it is unknown (and "undeclared") when you are not in that sub. Not even when you are inside a function called from that sub. The only variables that can be "seen" inside a Sub/Function are the ones that are declared at the module level (outside of sub/function), or within the sub itself.
Option Explicit means you must explicitly declare all variables and their types before using them. If you don't include the Option Explicit declaration, then VBA will just create Variant type variables whenever it encounters a new identifier.
So for example, you need to include Dim iLoopControl as Integer if you have declared Option Explicit:
Option Explicit
Dim iLoopControl As Integer
For iLoopControl = 1 To NoOfDice
Dice = Dice + WorksheetFunction.RandBetween(1, DiceSize)
Next
If you didn't include Option Explicit then you could just use iLoopControl without using the Dim iLoopControl as Integer to declare it.
You need to declare variables before using it
Where's End Sub for MercOne()?

Reusing an Array With Functions

I have two different functions that require access to the same array (the array isn't a constant; it will be edited and appended to whenever the function is used within a cell in the sheet).
I want to make this array available to both of them. The array needs to be multi-dimensional (or be a UDT that can have multiple elements within it, like I tried in my code below), and it needs to be able to be dynamically resized. Here is some sample code (edited a bit) I have, but it doesn't seem to work properly.
Option Base 1
Private Type PathsArray
Nodes() As String
End Type
' Instantiate the global array
Dim Paths(1 To 1) As PathsArray
Function SETTWENTY()
' Increase size of the array, preserving the current elements already inside it
ReDim Preserve Paths(1 To UBound(Paths) + 1)
' Make the inner array be 20 elements long
ReDim Preserve Paths(UBound(Paths)).Nodes(1 to 20)
' Return something random
GETPATH = UBound(Paths)
End Function
Function SETTHIRTY()
' Increase size of the array, preserving the current elements already inside it
ReDim Preserve Paths(1 To UBound(Paths) + 1)
' Make the inner array be 30 elements long
ReDim Preserve Paths(UBound(Paths)).Nodes(1 to 30)
' Return something random
GETPATH = UBound(Paths)
End Function
Anyone know why this won't work?
The root of your problem is that you are trying to resize a "static" module-level array. Here is a good description (from Chip Pearson) of the difference between "static" and "dynamic" VBA arrays:
http://www.cpearson.com/excel/vbaarrays.htm
You have a secondary problem in that your functions will return the VBA value Empty instead of the number of paths. In VBA, you return a value from a function by assigning the value to the name of the function.
In the code below, I fixed those problems by:
making the module-level array "dynamic"
adding an "init" routine to get your initial element in there
returning the values you expect from your functions
You might not really need (2) if your original (1 To 1) declaration wasn't really what you wanted anyway.
Note the use of Option Explicit re: (3). If you'd had that there, your original code with the "GETPATH" assignments would fail to compile, even after fixing (1).
Option Explicit
Option Base 1
Private Type PathsArray
Nodes() As String
End Type
' Just declare the module-level array
Dim Paths() As PathsArray
Public Sub init()
ReDim Paths(1 To 1) As PathsArray
End Sub
Function SETTWENTY()
' Increase size of the array, preserving the current elements already inside it
ReDim Preserve Paths(1 To UBound(Paths) + 1)
' Make the inner array be 20 elements long
ReDim Preserve Paths(UBound(Paths)).Nodes(1 To 20)
' Return something random
SETTWENTY = UBound(Paths)
End Function
Function SETTHIRTY()
' Increase size of the array, preserving the current elements already inside it
ReDim Preserve Paths(1 To UBound(Paths) + 1)
' Make the inner array be 30 elements long
ReDim Preserve Paths(UBound(Paths)).Nodes(1 To 30)
' Return something random
SETTHIRTY = UBound(Paths)
End Function

Resources