Redim array after it is filled - vba

Before filling my array I don't know how big it's going to get, but at a certain point (after all data has been inserted) I want to redim the array so there are no empty values in the end of the array. If I dim it as
valuesForSix() As Double
I cannot add values with
valuesForSix(0) = 9.654
Can somebody help me?

ReDim it!
Dim valuesForSix() As Double
ReDim valuesForSix(1) As Double
valuesForSix(0) = 9.654
valuesForSix(1) = 10.25
ReDim Preserve valuesForSix(10) As Double
Debug.Print valuesForSix(0)
Debug.Print valuesForSix(1)
The "Preserve" Keyword means that existing data is kept if the array size is increased.

You can use ReDim Preserve to redefine the array's dimensions. The Preserve keyword means the array retains all existing data. See this MSDN language reference for details.
This example initialises an empty array, then loops from 1 to 10 adding an extra element each time:
Dim v() As Double, i As Long
For i = 1 To 10
ReDim Preserve v(1 To i) As Double
v(i) = i
Next i
' v = [1 2 3 4 5 6 7 8 9 10]
You can extend the array by n elements using LBound and UBound:
Dim v(0 To 10) As Double, n As Long
n = 7
ReDim Preserve v(LBound(v) To UBound(v) + n)
' Now v is Double(0 to 17)

Related

Issue with Redim Preserve (2D array)

Yet another topic with multidimensional array and Redim Preserve, I know. I read a lot of them but still can not understand why my code is not working.
I kwow that you can only extend the last dimension and it is what I want: add a new column to my 2D array.
In order to isolate the issue, I test 2 code:
Sub test_Redim_Preserve()
Dim arr() As Variant
ReDim arr(10, 10)
ReDim Preserve arr(UBound(arr,1), UBound(arr,2) + 1)
End Sub
This work fine
Sub test_Redim_Preserve2()
Dim arr() As Variant
ReDim arr(10, 10)
arr = Range("A1:J10")
ReDim Preserve arr(UBound(arr,1), UBound(arr,2) + 1)
End Sub
This give me an error.
I just gave a range to populate my array and then I can´t Redim it. I don´t understand what is missing for it to accept the Redim.
Could someone explain me?
The default lower bound, in the absence of an Option Base statement to the contrary, is 0 but you assign a range to an array, it always has a lower bound of 1, so your code is actually trying to resize the first dimension of the array too by altering its lower bound. Use:
ReDim Preserve arr(1 To UBound(arr, 1), 1 To UBound(arr, 2) + 1)
You can use Option Base 1 at the top of your code, and then your original code will work fine.
Full code:
Option Base 1
Sub test_Redim_Preserve2()
Dim arr() As Variant
ReDim arr(10, 10)
arr = Range("A1:J10")
ReDim Preserve arr(UBound(arr, 1), UBound(arr, 2) + 1)
End Sub

Type mimsatch when assigning result of MMult to an array variable

Apologies for the newbie question, but I couldn't find an answer when searching.
I'm fairly new to matrix manipulation in VBA. I keep on getting a type mismatch with the following code.
Sub matrixtest()
Dim matrix1() As Integer
Dim matrix2() As Integer
Dim matrix3() As Integer
Dim i, j, k As Integer
'populate matrix1
ReDim matrix1(3, 3)
For j = 1 To 3
For i = 1 To 3
matrix1(i, j) = Range("C5").Offset(i - 1, j - 1)
Next i
Next j
'populate matrix2
ReDim matrix2(3, 3)
For j = 1 To 3
For i = 1 To 3
matrix2(i, j) = Range("G5").Offset(i - 1, j - 1)
Next i
Next j
ReDim matrix3(3, 3)
matrix3 = Application.WorksheetFunction.MMult(matrix1, matrix2)
End Sub
If you replace the line
matrix3 = Application.WorksheetFunction.MMult(matrix1, matrix2)
By
Debug.Print TypeName(matrix3 = Application.WorksheetFunction.MMult(matrix1, matrix2))
The output is:
Variant()
Which can't be assigned to an Integer().
I would recommend replacing
Dim matrix1() As Integer
Dim matrix2() As Integer
Dim matrix3() As Integer
Dim i, j, k As Integer
by
Dim matrix1, matrix2, matrix3 As Variant 'note lack of ()
Dim i, j, k As Long 'Integer is borderline obsolete in VBA
Variants do a nice job of holding and passing arrays and tend to handle any needed type conversions automatically. When dealing with arrays in VBA, I tend to use them almost exclusively. For one thing, it makes it easy to load arrays from ranges.
Just use ReDim to make the variants hold arrays:
ReDim matrix1(1 to 3, 1 to 3) 'doesn't hurt to be explicit about lower bounds
ReDim matrix2(1 to 3, 1 to 3)
'load arrays...
'no need to redim matrix3, just:
matrix3 = Application.WorksheetFunction.MMult(matrix1, matrix2)
There is an even shorter way of doing what you are trying to do:
matrix1 = Range("C5:E7").Value
matrix2 = Range("G5:I7").Value
matrix3 = Application.WorksheetFunction.MMult(matrix1, matrix2)
In the above code you don't need to use any preliminary ReDim. When you want to load the values of a rectangular range into a variant in VBA, you don't need to loop, which is needlessly slow. Just assign the values in one fell swoop.

Issue with nested For/Next loop and filling array

I am working in VBA assignment and need to make an array that auto populates the values 16 to 9 in reverse order. this is my current code:
nTeams = 16 ' variable to enable other size brackets
ReDim arrBracket(nTeams / 2) '<< ReDim array to appropriate size
'***** Fill the array where element 1 of the array holds the value of the
' lowest seed (e.g. if 16 teams, element 1 has a value of 16)
' vvv your For/Next loop below
Dim nTeams2 As Integer ' Place holder for For/Next loop
For i = 1 To (nTeams / 2)
For nTeams2 = nTeams To (nTeams / 2) Step -1
arrBracket(i) = nTeams2
Next nTeams2
Next i
The issue is that it now is only filling the array with the number 8 for each of the 8 elements, rather than 16, 15, 14, 13, etc.
Here is the loop my professor included to check the work:
For i = LBound(arrBracket()) To UBound(arrBracket()) ' loops through the array
Debug.Print i & " vs " & arrBracket(i) ' sends array info to immediate window
Next i
You don't need to set nested loops for that. You can do that only with inner for loop. Here you go.
nTeams = 16 ' variable to enable other size brackets
ReDim arrBracket(nTeams / 2) '<< ReDim array to appropriate size
Dim i As Integer
Dim nTeams2 As Long
i = 0
For nTeams2 = nTeams To (nTeams / 2) Step -1
arrBracket(i) = nTeams2
i = i + 1
Next nTeams2

Debugging VBA code - appending values to array

I am trying to use code of the following form to populate an array of x rows:
Dim myarray() As Variant
Dim string1 As String
Dim myarray_ubound As Integer
myarray_ubound = 0
For i = 1 to x
myarray_ubound = myarray_ubound + 1
ReDim Preserve myarray(1 To myarray_ubound, 1 To 2)
myarray(myarray_ubound,1) = i
myarray(myarray_ubound,2) = string1
Next i
However, when I run it it gets stuck after the first loop, telling me that a subscript is out of range. Debugging takes me to the ReDim command.
I used myarray_ubound as an alternative to calling the UBound function many times, but I have tried using this as well and I get the same error.
Can anyone spot what's gone wrong?
See: http://msdn.microsoft.com/en-us/library/aa266231.aspx
"If you use the Preserve keyword, you can resize only the last array dimension and you can't change the number of dimensions at all."
Try
ReDim Preserve myarray(1 To 2, 1 To myarray_ubound)
instead.
you can only redim the last element of the array (not the first), see below. As you know x I would suggest to redim your array with this value from the beginning.
Dim myarray() As Variant
Dim string1 As String
Dim myarray_ubound As Integer
myarray_ubound = 0
For i = 1 To 10
myarray_ubound = myarray_ubound + 1
ReDim Preserve myarray(1 To 2, 1 To myarray_ubound)
myarray(1, myarray_ubound) = i
myarray(2, myarray_ubound) = string1
Next i
Since you are declaring the variable as a Variant i don't see why you need to re-dim. (maybe related to memory issues, feel free to fill in).
I would suggest:
For i = 1 to 10
myArray(1, i-1) = i
myArray(2, i-1) = string1
next i

Programming WLS function excel vba

I am attempting to replicate a function for WLS (Weighted Least Squares) that I have found in a textbook in excel. There is a value error coming up and I think that I am doing something wrong in using the function.
The following is the VBA code for a supporting function Diag(w) and the function itself WLSregress():
Function Diag(W) As Variant
Dim n, i, j, k As Integer
Dim temp As Variant
n = W.Count
ReDim temp(n, n)
For i = 1 To n
For j = 1 To n
If j = i Then temp(i, j) = W(i) Else temp(i, j) = 0
Next j
Next i
Diag = temp
End Function
Function WLSregress(y As Variant, X As Variant, W As Variant) As Variant
Wmat = Diag(W)
n = W.Count
Dim Xtrans, Xw, XwX, XwXinv, Xwy As Variant
Dim m1, m2, m3, m4 As Variant
Dim output() As Variant
Xtrans = Application.Tranpose(X)
Xw = Application.MMult(Xtrans, Wmat)
XwX = Application.MMult(Xw, X)
XwXinv = Application.MInverse(XwX)
Xwy = Application.MMult(Xw, y)
b = Application.MMult(XwXinv, Xwy)
k = Application.Count(b)
ReDim output(k) As Variant
For bcnt = 1 To k
output(bcnt) = b(bcnt, 1)
Next bcnt
WLSregress = Application.Transpose(output)
End Function
This function should return the WLS estimator for the explanatory variables of equation being estimated. I understand the code leading up to the k = Application.Count(b) line but not too sure how the output bit is working.
If anyone could help me figure out why this isn't working I would be very grateful.
The following is an example image of the function trying to work.
By default, Excel will start sizing its arrays with 0 if you don't indicate otherwise. For example,
Redim arr(2,2)
will actually give you a 3 x 3 array
0 1 2
0 blank | blank | blank
1 blank | blank | blank
2 blank | blank | blank
Because of this, when you have ReDim temp(n, n), you're actually creating an array with one more row and column than you actually want. In your example, you would expect the Dialog for A3:18 to be a 16 x 16 dialog, but it will actually create a 17 x 17 dialog, throwing off your matrix multiplications (i.e. Application.MMult)
Replace this line
ReDim temp(n, n)
With this line
ReDim temp(1 to n, 1 to n)
And you should now get results returned. Up to you to determine whether the result is accurate or not.