I was just doing some yicky code and I thought, instead of using three dynamic arrays, as such:
dim x() as string, y() as string, z() as string
It will be nicer to have a 3 dimensional dynamic array. But; the help and my fumbling experiments has not revealed the method of defining them.
This does not work:
dim x()() or dim(,2) or dim(,)
Any ideas anyone?
A dynamic array is declared the same way regardless of the number of dimensions (arrays in LotusScript can have up to 8 dimensions). According to your example I think it is a two dimensional array you want, where the first dimension is limited to three entries.
If you first declare the array as:
Dim x() As String
You can then specify bounds according to the following example:
Redim x( 0 To 2, 0 To 9 ) ' A two dimensional array
And if you need to enlarge the array later (and keep all the values) you can do it like this:
Redim Preserve x( 0 To 2, 0 To 99 )
Please keep in mind that only the bounds of last dimension can be changed once the number of dimensions of the array has been set.
You could use lists instead of arrays.
Dim x list as String
That is fully dynamic and takes a string as index. List can't contain lists, but lists can contain objects, so you might want to do
Public Class ListContainer
Public level2 List as String
End Class
This way you never need to REDIM preserve. A forall loops you savely through a list
Related
This question already has answers here:
How to initialize a multidimensional array variable in vba for excel
(5 answers)
Closed 1 year ago.
in python it is possible to declare a list in a list for example like this
l=[[1,0,0],[0,1,0],[0,0,1]]
how do i do the same but in VBA excel
Declaring an array in VBA is different from initializing its contents (unlike python).
You declare a variable to be a 2D array of size N, M with
Dim a(1 to N, 1 to M) as Variant
but this creates a fixed sized array and not a dynamic array. It is better to declare an array as follows
Dim a() as Variant
ReDim a(1 to N, 1 to M)
and to fill the array with values you need a double loop, or assigning elements manually
a(1,1) = ...
a(1,2) = ...
Notice that I declared arrays that are 1-based, instead of 0-based (first element is a(1,1), and not a(0,0)) because when reading in a table from an Excel worksheet with
a = Range("A2").Resize(N,M).Value
Debug.Print a(3,1)
it creates such an array.
Note that it is possible to declare a dynamic array and fill it in with jagged form (array of arrays) using the following code
Dim a() as Variant
a = Array( Array(1,2,3), Array(4,5,6), Array(7,8,9) )
which you have access to in VBA with the following form
Debug.Print a(2)(0)
' 7
Notice that they arrays produced by the Array() command are 0-based with indexes varying between 0..N-1. Additionally, since the above is jagged array (array of arrays), the elements are accessed using sequential indexers as in a(i)(j) instead of a(i,j)
So it really depends on how you want to use the 2D array to decide how to best declare it.
I have a short question about ReDim-ming dynamic arrays - more precisely in which cases is it required?
I understand I need to ReDim Preserve array(x) As Variant when adding entries into the array. Adjusting/changing existing information in an array works well like: array(x) = "Added text " & array(x)
But are there any other cases when I need to worry about ReDim or maybe even other special requirements when handling dynamic arrays?
I'm writing a code which will include large dynamic arrays that get data added from many different sources before For-looping through it to write the date into a list on another sheet. I can't let an error pop up in the future because I missed something.
ReDimis used to change the size of an array. You can ReDim an array not initialized like this:
Dim arr() As Variant
x = 200
ReDim arr(1 to x)
You can also do this on initialized arrays:
Dim arr(1 to 2) As Variant
ReDim arr(1 to 5) <-- will delete previous stored values
ReDim Preserve arr(1 to 5) <-- will preserve previous stored values
Note that using the Preserve will only change the last dimension on multidimension arrays, so Dim arr(1 to 5, 1 to 2) if you want to keep your data using ReDim Preserve you can only change the second dimension from 1 to 2 to 1 to x.
Like Tom said, changing the size of your array in every loop will impact on the performance so you should first calculate the maximum size of your array and then dimension it, or dimension the size way over what you need and lastly redim it to your needs when you end.
It is easy creating an array in MS Excel VBA, be it 1-dimensional or multi-dimensional, and set it to type Integer or String. Is it possible to do complex arrays however along these lines (this is not true code but represents what I mean):
1 to 100 rows
1 to 100 columns
f_Depth: Float
1 to 4 points
l_X: Long
l_Y: Long
The Excel integer-only (or float-only or whatever you choose) makes it very difficult to work with the code.
By "complex array" do you mean array of mixed type? If so, you can use Collection which accepts objects of any type:
Dim Data As New Collection
Data.Add (1)
Data.Add ("Hello world")
Data.Add (3.14)
I'm running out of memory (I have 16GB) in a script I am running. Here is a little background:
I am generating an array that is ~150k rows by 8 column as the basis for my calculations.
Then, for each "row" of values (nothing is ever written to the worksheet), I am making a LOT of calculations, which I am storing in various data structures (I have 3 main structures at this point). One of these structures is composed of the following:
A Variant Array with 150k Dictionaries. Each Dictionary has ~4 Key-Item pairs. Each item in each dictionary is another dictionary, containing exactly 9 key-item pairs. All keys are Strings and all items are Doubles.
Essentially, this is the same thing as:
Dim Array(1 to 150000, 1 to 4, 1 to 9) as Double
Except I want to be able to reference the values with text strings -- hence the dictionaries.
An example would be
Value = Array(2401)("Key1")("Key2")
I wouldn't think this would be too much for VBA to handle -- we're talking 150,000 * 4 * 9 individual doubles = 5.4M doubles for each of the 3 main data structures. I don't have that much experience with programming and memory management, but sure that wouldn't consume 16GB of memory!
As such, I'm thinking there's a problem in how I'm generating these data structures that is causing a memory leak somewhere.
Essentially the loop looks like this
Dim TempDict1 as Dictionary
Dim TempDict2 as Dictionary
Dim FinalArray() as Variant
ReDim FinalArray(1 to 150000) as Variant
Dim Calculations as Double
For i = 1 to 150000
Set TempDict = NewDictionary
for j = 1 to 5
Set TempDict2 = NewDictionary
for k = 1 to 9
Calculations = 2*2
TempDict2.Add Key:= KeyK, Item:= Calculations
Next k
TempDict.Add Key:= KeyJ, Item:= TempDict2
' TempDict2.RemoveAll (This causes an error)
next j
Set FinalArray(i) = TempDict
' TempDict.RemoveAll (This causes an error)
Next i
What am I doing wrong here? I've tried destroying the temporary dictionaries after adding them to the parent item, but that actually gives me a type error.
UPDATE: I've tried setting the temporary dictionaries to nothing instead of removing all. This doesn't cause any errors, but it still consumes a lot of memory. With 37k iterations, it consumes 8.4GB of memory.
I'm not sure if this is some sort of bug or memory leak, but the fact is that this is an extremely memory-inefficient way to store data.
As such, I've edited the code to use 3 dimensional arrays with separate dictionaries to associate the indices of arrays with text strings, which is working great.
I was able to store 8 different 3D arrays (150k by 8 by 13) and 7 different 2D arrays (150k 13), both of doubles. Overhead doesn't seem to be too high. Given a size of 8 bytes per double, theoretical memory usage is 1.11GB, which isn't too bad.
i want to be able to initialize an array to store the values of a conversion. but i don't know how many values there will be until compile time so i want the range to go from
pseudo-code:
1 to <some expression>
namely i want it as
Dim Colvals(1 To Len(EndColumn)) As Integer
but when the code is sent to compile it throws
Constant Expression required
any idea how to do it? i really don't want to limit the versatility of the program by forcing the specification of the range.
You want to redimension your array using a Redim statement:
Dim Colvals() As Integer
ReDim Colvals(1 To Len(EndColumn))
It seems strange that it requires a Constant for the Dim and not the Redim, but it's true.