I just started a new job and am trying to use VBA within excel to store values within a multidimensional array.
so I first want to search through a column for values and as they occur, i want to store them once, and assign a product number that will increment each time it encounters a new unique String value in the column. then just print the number to the cell and only change it as it increments/
the values will be Strings, (product styles). the product number will be a number.(int)
will it be possible to do this in VBA for excel. I read online you can't use different data types in the same array.
sorry new to VBA and any help would be great. if i would be better off to use a normal function in excel let me know.
You can declare you array as Variant and then you can store different types in the Array. For example
Sub test()
Dim arr() As Variant
Dim i As Long
ReDim arr(0 To 1)
arr(0) = "hi"
arr(1) = 1
For i = LBound(arr, 1) To UBound(arr, 1)
Debug.Print arr(i)
Debug.Print VarType(arr(i))
Next
End Sub
This prints in the immediate window the following
hi
8 ' This corresponds to the type String
1
2 ' This corresponds to the type Integer
EDIT
As per the question, yes you can have different types of arrays as entries in an Variant-Array. For example:
Sub test2()
Dim arr As Variant
Dim str_a(3) As String
Dim lng_a(8) As Long
Dim i As Long, j As Long
For i = LBound(str_a, 1) To UBound(str_a, 1)
str_a(i) = "hi " & i
Next
For i = LBound(lng_a, 1) To UBound(lng_a, 1)
lng_a(i) = i
Next
ReDim arr(0 To 1)
arr(0) = str_a
arr(1) = lng_a
For i = LBound(arr, 1) To UBound(arr, 1)
Debug.Print VarType(arr(i))
For j = LBound(arr(i), 1) To UBound(arr(i), 1)
'Do Stuff with the arrays
Next
Next
End Sub
This prints
8200
8195
An array always has the VarType 8192 + the value of type. For example String has the Value of 8, therefore an array of Type String has 8200 (8192+8).
Related
I'm stuck with a problem when I'm working with a dictionary in VBA. The reason why I want to work with a dictionary and a do-while loop is because I have variables with different length, that I want to loop through.
First I want to give the dic keys and and items.
The reason why I skip one col for each loop is because each series has a col with dates and then a col with prices. If it is possible I want to capture the dates that match the prices in the same dictionary.
Sub opg1(dicSPX As Object)
Dim i As Integer, m As Integer
Dim varColLeng As Variant
Set dicSPX = CreateObject("Scripting.Dictionary")
m = 10
Sheets("Data").Activate
ReDim intCol(1 To nCol)
'opretter dictionary
ReDim n(1 To m)
Do While n <> ""
For i = 1 To mn
' redim preserve IntColLen
dicSPX.Add Cells(1, 2 + ((i - 1) * 2)).Value, Range(Cells(9, 2 + ((i - 1) * 2)), Cells(n, 2 + ((i - 1) * 2))).Value
Next i
Loop
End Sub
then I want to execute a procedure for all keys in my dic. I want to compute returns in different time series.
However, when I call the dic, to the sub Returns() I get an error (Compile error: Variable not defined). I'm new to dictionaries and I probably missed a small detail.
Sub Returns()
Call opg1(dicSPX)
Dim dicSPX As New Scripting.Dictionary
Dim varKey As Variant, varArr As Variant
For Each varKey In dicSPX
varArr = dicSPX(varKey)
For i = LBound(varArr, 1) To UBound(varArr, 1)
For j = LBound(varArr, 2) To UBound(varArr, 2)
' varReturns(i,j) = compute the return here
Next
Next
Next
Any suggestions? I hope the question is clear.
Thank you
It should be clear which variable is not defined by the line which is highlighted after the error is thrown. At a quick glance I can tell that you didn't define i or j:
Sub Returns()
Dim dicSPX As New Scripting.Dictionary
opg1(dicSPX)
Dim varKey As Variant
For Each varKey In dicSPX
Dim varArr As Variant
varArr = dicSPX(varKey)
Dim i As Long
For i = LBound(varArr, 1) To UBound(varArr, 1)
Dim j As Long
For j = LBound(varArr, 2) To UBound(varArr, 2)
varReturns(i,j) = compute the return here
Next
Next
Next
End Sub
You should always explicitly define each variable, one line at a time, right before they are used. This way the declaration is always near the usage so you can see it on the same page.
You should also make opg1 a function that returns a dictionary. That would clarify your intent. Passing a variable by reference makes it harder to tell how the program works to the reader.
I have a column that contains mixed strings and I need to find all the unique strings and declare to either a string or array variable. The last row of the column will vary so I cannot use a definite range. I was thinking of using some form of string comparison of the preceding cell and current cell, but like I said the data is mixed so when redundant data comes up this complicates the problem. Here is a picture to try and explain it better.
EDIT: The string concatenation I will worry about that later.
Using Excel 365.
With data in A1 through A11, in another cell enter:
=UNIQUE(A1:A11)
to get:
or:
=TEXTJOIN(",",TRUE,UNIQUE(A1:A11))
to get a comma-separated list:
EDIT#1:
With VBA, try this UDF:
Public Function unikue(rng As Range)
Dim arr, c As Collection, r As Range
Dim nCall As Long, nColl As Long
Dim i As Long
Set c = New Collection
nCall = Application.Caller.Count
On Error Resume Next
For Each r In rng
c.Add r.Text, CStr(r.Text)
Next r
On Error GoTo 0
nColl = c.Count
If nCall > nColl Then
ReDim arr(1 To nCall, 1 To 1)
For i = 1 To nCall
arr(i, 1) = ""
Next i
Else
ReDim arr(1 To nColl, 1 To 1)
End If
For i = 1 To nColl
arr(i, 1) = c.Item(i)
Next i
unikue = arr
End Function
I am trying to write 3 user defined type variables which need to be associated with each other like this;
Type tdrivers
Strfirstname as string
Strsurname as string
Intage as integer
End type
Type Tcars
Strmake as string
Strmodel as string
Lngcc as long
Driverid() as tdrivers
End type
Type T_Race
Strlocation as string
DteRacedate as date
IntYear as integer
CarsID() as Tcars
End Type
Sub CreateRace()
Dim myrace() as T_Race
'Variables to hold integer 'values at runtime
Dim A as integer
Dim B as integer
Dim C as integer
'this line redims myrace ok
Redim myrace(A)
'This line doesn't do anything
'When I try to redim the 'carsID() array nested inside 'the myrace(A) like so;
Redim myrace(A).carsID(B)
'This line obviously does 'nothing either
Redim myrace(A).CarsID(B).driverid(C)
I need to be able to assign races to the myrace() array and then assign cars to each race they have taken part in and then drivers to cars they have driven. So the carsID() must be nested within myrace() and driverid() nested within carsID()
Once I know how to redim carsID() in can then redim Driverid() which is nested further within.
If I make all the arrays fixed with a constant value such as 8 then the sub runs ok and all races, cars and drivers are nested correctly. Its the redim on nested dynamic arrays that is failing. Hope this makes sense. Can anyone help. Thanks
The point is that you have to ReDim every sub-array individually. The following example initializes all sub arrays and prints them at the end:
Sub Example()
Dim i As Integer
Dim j As Integer
Dim k As Integer
ReDim myRace(5)
For i = 1 To 5
ReDim myRace(i).CarsID(5)
For j = 1 To 5
ReDim myRace(i).CarsID(j).Driverid(5)
For k = 1 To 5
myRace(i).CarsID(j).Driverid(k).Strfirstname = Chr(k + Asc("a")) & Str(i) & Str(j) & Str(k)
Next k
Next j
Next i
' Now print it
For i = 1 To 5
For j = 1 To 5
For k = 1 To 5
Debug.Print myRace(i).CarsID(j).Driverid(k).Strfirstname
Next k
Next j
Next i
End Sub
I am working on a program that needs to read an array of values from cells in another worksheet in the same workbook. I am able to read a single value just fine, but when I try to read multiple, I cannot return an array.
Here is what I am trying to do:
Dim list() As Variant
list = ActiveWorkbook.Worksheets("Sheet2").Range("A2:C2").value
Debug.Print TypeName(list)
Debug.Print UBound(list)
Debug.Print LBound(list)
Debug.Print TypeName(list(UBound(list)))
For which the output is:
Variant()
1
1
Subscript out of range
However, If I try it where I expect a single string, instead of an array of strings
Dim value As String
Let value = ActiveWorkbook.Worksheets("Site IDs and CJONs").Range("A2").value
Debug.Print TypeName(value)
Debug.Print value
for which I get the output
String
Expected Value
According to this question I should be able to simply return an array from the range function (example from the answer below), but it doesn't seem to be working for me. What am I doing wrong?
Dim DirArray As Variant
DirArray = Range("a1:a5").Value
Although it is not obvious, this:
Dim DirArray As Variant
DirArray = Range("a1:a5").Value
actually is like:
Dim DirArray(1 To 5, 1 To 1) As Variant
DirArray(1, 1) = Range("A1").Value
DirArray(2, 1) = Range("A2").Value
DirArray(3, 1) = Range("A3").Value
DirArray(4, 1) = Range("A4").Value
DirArray(5, 1) = Range("A5").Value
Pulling a set of cells into an array usually makes a 2-D array.
NOTE:
If you want to go from array to worksheet cells then, for example:
Sub ytrewq()
Dim DirArray(1 To 5, 1 To 1) As Variant
DirArray(1, 1) = "Larry"
DirArray(2, 1) = "Moe"
DirArray(3, 1) = "Curly"
DirArray(4, 1) = "Shepp"
DirArray(5, 1) = "James"
Range("B9").Resize(5, 1) = DirArray
End Sub
I might as well put my comment as an answer:
Option Explicit
Sub test()
Dim list As Variant
list = Application.Transpose(Application.Transpose(ActiveWorkbook.Worksheets("Sheet1").Range("A2:C2").Value))
Debug.Print TypeName(list)
Debug.Print UBound(list)
Debug.Print LBound(list)
'Debug.Print UBound(list, 2) Error
'Debug.Print LBound(list, 2) Error
Debug.Print TypeName(list(UBound(list)))
Debug.Print list(UBound(list))
End Sub
Gives output:
Variant()
3
1
String
x
where C2 contains letter x.
I saw array() = range().value in an example and I'm trying to understand how it works.
Sub test()
Dim arr() As Variant
arr() = Range("E5:E7").Value
For i = 0 To UBound(arr)
Debug.Print arr(i)
Next i
End Sub
First, above code is giving me subscript out of range error. How come ? Second, what part of the documentation would let me know how array() = range().value would play out without testing it ? My hypothesis is that it will go through the cells from the top left to the bottom right and add them to the array. How can I confirm that though ?
I see two issues with your code. The first is that you start i at 0, but arrays in Excel begin at index 1. Instead of For i = 0 you can use For i = LBound(arr) like you use UBound(arr) or just start it at 1.
Second, and more importantly, an array of cells has both columns and rows. When you read a range into a variant array, you get a two-dimensional result (rows and columns) and not a one-dimensional result as you seem to be expecting.
Try this:
Sub test()
Dim arr() As Variant
Dim i As Long, j As Long
arr() = Range("E5:E7").Value
For i = 1 To UBound(arr, 1)
For j = 1 To UBound(arr, 2)
Debug.Print arr(i, j)
Next j
Next i
End Sub
If you want to get just the values of the cells into a one dimensional array, you can do that by using the Transpose function, like this:
arr() = Application.WorksheetFunction.Transpose(Range("E5:E7").Value)
If you do this, the array is now one-dimensional and you can iterate through it like you were trying to.
arr() = Application.WorksheetFunction.Transpose(Range("E5:E7").Value)
For i = 1 To UBound(arr)
Debug.Print arr(i)
Next i
This is a good read for you: http://www.cpearson.com/excel/ArraysAndRanges.aspx
The reason you're getting "out of range" is because it returns a 2 dimensional array.
Your line of code For i = 0 To UBound(arr) should be For i = 1 To UBound(arr,1)
Also, the array starts at 1, so don't use the 0 For i = 1 to UBound(arr, 1)
Your corrected code would be:
Sub Test()
Dim arr() as Variant
arr = Range("E5:E7")
For i = 1 To UBound(arr, 1)
MsgBox (arr(i, 1))
Next i
End Sub
It's basically loading the cell values of E5 - E7 into an array. But it is going to be two dimensional. So you will need Debug.Print arr(i, 1)
Sub test()
Dim arr() As Variant
arr() = Range("E5:E7").Value
For i = 1 To UBound(arr)
Debug.Print arr(i, 1)
Next i
End Sub