I have a list of arrays. I am looping through to write the data in the arrays into a text file. When I loop through each time, I would like to use a different array to access the data.
I am thinking of storing the names of these arrays in an different array and as I loop through, I can access this array using the current loop index. But I am not sure how to do this in VBA.
Need some guidance on this. I am welcome to other suggestions as well.
You could also store them in a collection. This will also allow you to add a key to each array that you store in the collection. You can than even call a specific array using this key. Just a short example to get you started:
Sub CreateCollection()
Dim col As Collection
Dim arr As Variant
Dim MyArray1(1) As String
Dim MyArray2(1) As String
MyArray1(0) = "FirstItemArr1"
MyArray1(1) = "SecondItemArr1"
MyArray2(0) = "FirstItemArr2"
MyArray2(1) = "SecondItemArr2"
Set col = New Collection
col.Add MyArray1, "ArrayName1"
col.Add MyArray2, "ArrayName2"
For Each arr In col
Debug.Print arr(1)
Next
Debug.Print col("ArrayName2")(1)
Set col = Nothing
End Sub
Related
I have an array as shown in the screenshot:
I am trying to iterate through this array, but I am unable to manage the dimension setting. Haven't seen an array like that before.
It will be creating while using the Split-function of VBA. How am I able to iterate through to second dimension?
Code snippet:
Dim arrTemp() As Variant: arrTemp = tblUserInput.DataBodyRange
Dim arr() As Variant
Dim arrtemp_Sheet() As Variant
Dim arrtemp_Control() As Variant
iCounter = 0
For i = LBound(arrTemp) To UBound(arrTemp)
If Not arrTemp(i, 5) = "" Then
iCounter = iCounter + 1
ReDim Preserve arrtemp_Sheet(1 To iCounter)
ReDim Preserve arrtemp_Control(1 To iCounter)
arrtemp_Sheet(iCounter) = Split(arrTemp(i, 5), ";")
arrtemp_Control(iCounter) = Split(arrTemp(i, 6), ";")
End If
Next i
Dim arrFinal_Sheet() As Variant
For i = LBound(arrtemp_Sheet) To UBound(arrtemp_Sheet)
For j = LBound(arrFinal_Sheet(i)) To UBound(arrFinal_Sheet(i)) <-- Error!
Debug.Print arrFinal_Sheet(i, j)
Next j
Next i
Background information:
I need all entries in that list being populated into an array one by one. and if a cell contains a ";", then I need to split it and put it also one after another into the array.
This is why I first create a temporary Array which collects the sheets and another temporary array which collects the controls names. I then want to merge them into a final array. Maybe there is even a better approach?
I am trying to create arrays of specific length dynamically, so that I can use them in a bigger procedure.
Sample Data:
The below code using the Dictionary Gives me the Count and Unique File Extensions in the Data.
Code:
Dim dict As New Scripting.Dictionary
For Each cel In Range("B1:B8")
I = 1
If Not dict.Exists(cel.Text) Then
dict.Add cel.Text, I
Else
temp = dict(cel.Text) + 1
dict.Remove cel.Text
dict.Add cel.Text, temp
End If
Next cel
For Each varKey In dict.Keys
Debug.Print varKey & ":" & dict.Item(varKey)
Next
Result:
What I am trying to do is create 3 (in this sample) arrays pdf(4),xlsx(3),docm(1)
Using the results from Dictionary.
But the line Dim varkey(dict.Item(varKey)) As Variant gives me Compile Error.
Constant Expression Required
Is there a way to do it ? I searched google for ways to achieve this, but with no luck.
Basically what I want is to use these different extension names to declare Arrays. But these extension names will vary so I need to declare them dynamically. Array should have same name as the Extension.
So pick the name from sheet or from Dictionary and declare that as Array of a specified Length. Length can be Redim'ed afterwards also, but the main problem is declaring them from a variable.
As BrakNicku commented a Dictionary of Dictionaries will get you the answer that you want.
Sub PrintExtensionCount()
Dim Cell As Range
Dim Map As New Scripting.Dictionary, subMap As New Scripting.Dictionary
For Each Cell In Range("B1:B8")
If Not Map.Exists(Cell.Value) Then Map.Add Cell.Text, New Dictionary
Set subMap = Map(Cell.Value)
subMap.Add Cell.Offset(0, -1).Value, vbNullString
Next
Dim Key As Variant
For Each Key In Map
Set subMap = Map(Key)
Debug.Print Key; ":"; subMap.Count
Next
End Sub
Result
Not to confuse things but I like to use a Dictionary of ArrayList.
Sub PrintExtensionCount()
Dim Cell As Range
Dim Map As New Scripting.Dictionary, list As Object
For Each Cell In Range("B1:B8")
If Not Map.Exists(Cell.Value) Then Map.Add Cell.Text, CreateObject("System.Collections.ArrayList")
Set list = Map(Cell.Value)
list.Add Cell.Offset(0, -1).Value
Next
Dim Key As Variant
For Each Key In Map
Set list = Map(Key)
Debug.Print Key; ":"; list.Count
Next
End Sub
I'm not sure exactly what the task at hand is, but this is an X-Y problem, if I understand your comments.
Dim statements - declarative statements - are not executable. This is regardless of the type (String, Long, Variant array, whatever.) Your question title might have been bit misleading in that regard, since it seems like essentially you're trying to dynamically declare variables - the fact they are arrays is coincidental.
You can avoid the compile error by ReDimming an array based on the count from your dictionary, but you can't come up with a dynamic list of variables.
I have this code that populates an array with worksheet names, given a condition:
Dim lng_Counter As Long
Dim arr_wks() As Variant
lng_Counter = 1
For Each wks In ThisWorkbook.Worksheets
If Left(wks.Name, 2) = "Hi" Then
ReDim Preserve arr_wks(lng_Counter)
arr_wks(lng_Counter) = wks.Name
lng_Counter = lng_Counter +1
End if
Next wks
I would then like copy these worksheets to a new workbook and so I have tried something like this:
Sheets(arr_wks()).Copy
Which isn't working. The only way I can get it to work is to write out:
Sheets(Array(arr_wks(1),arr_Wks(2),...)).Copy
Which isn't useful as the size of the array will change depending on the number of sheets that meet the condition at a given time.
How can I feed the array into a Sheets(arr).Copy type argument?
You end up with an error where the first element (with an index of zero) is empty.
You can fix that with
lng_Counter = 0
, or
ReDim Preserve arr_wks(1 to lng_Counter)
, or
Option Base 1
on top.
I have two columns of dates up to 30k lines. I want to filter for one date in the second column and return all the unique dates from the first column.
I could build this in Access but I don't use Access for anything else so it seems overkill to use that. And partly because I am curious if I can do it in Excel.
I'd prefer not to use a loop because it will be expensive in terms of time to run and I am just learning about arrays and class modules so this is a great example.
There is some background on this already on SOF but it's not detailed enough for me - I'm unfamiliar with Class Modules
Filtering 2D Arrays in Excel VBA
Any help or pointers would be greatly appreciated.
Sub CreateUniqueTradeDatesForAsOfDate_test()
Dim InternalArray As Variant
Dim Rg_Internal As Range
Dim arr As New Collection
Dim myRow As Long
Dim myCol As Long
Set d = CreateObject("Scripting.Dictionary")
'set the range
Set Rg_Internal = Worksheets("Bloomberg").Range("G:H")
'Set the array to the range
InternalArray = Rg_Internal.Value
'Transpose the array
InternalArray = Application.Transpose(InternalArray)
'Create the unique
With CreateObject("scripting.dictionary")
For Each it In InternalArray
d = .Item(it)
Next
d = .Keys ' the array .keys contains all unique keys
End With
'print to the immediate window but all unique values of the array
' not just the unique values from the first column based on
'the criteria from the second column
For Each i In d 'To UBound(10, 1)
Debug.Print i; RowNos
Next i
End Sub
I have a spreadsheet of data that I want to put into a VBA array which then outputs unique values to a new sheet. I have got that to work so far. However, some of the cells in the original data have text separated by commas, and I want to add those to the array as well. I can't quite get that bit to work.
After the various 'dims', my code is
'Grabs the data to work with
Set rTable = Worksheets("Data Entry").Range("N1:N100", "P1:P100")
'Puts it into an array
MyArray = rTable.Value
'Sets where the data will end up
Set rCell = Worksheets("TestSheet").Range("A1:A100")
'Each unique entry gets added to the new array
On Error Resume Next
For Each a In MyArray
UnqArray.Add a, a
Next
'Add unique data to new location
For i = 1 To UnqArray.Count
rCell(i, 1) = UnqArray(i)
Next
I have tried doing a new variant to store the split data
SpArray = split(MyArray,", ")
and then have that here
MyArray = rTable.Value
SpArray = split(MyArray,", ")
and then refer to SpArray for the rest of the code
I've also tried to have as part of
For Each a in SpArray
but it doesn't work for me.
Do I need to do a separate loop on each cell of the array before I filter out the unique ones?
Yes, you need another loop. But if you set a reference to Microsoft Scripting Runtime and use a Dictionary object, you can eliminate the loop that writes to the range because Dictionary.Keys returns an array.
In this example, it attempts to split every entry on a comma and treats each of those as a unique. If there is no comma, Split returns the one value so it works in both cases. There's probably a small cost to splitting things that don't need to be split, but you won't notice until your range is much larger. And it makes the code cleaner, I think.
Sub WriteUniques()
Dim dcUnique As Scripting.Dictionary
Dim vaData As Variant
Dim vaSplit As Variant
Dim i As Long, j As Long
vaData = Sheet1.Range("$I$12:$I$62").Value
Set dcUnique = New Scripting.Dictionary
For i = LBound(vaData, 1) To UBound(vaData, 1)
vaSplit = Split(vaData(i, 1), ",")
For j = LBound(vaSplit) To UBound(vaSplit)
If Not dcUnique.Exists(vaSplit(j)) Then
dcUnique.Add vaSplit(j), vaSplit(j)
End If
Next j
Next i
Sheet1.Range("J12").Resize(dcUnique.Count, 1).Value = Application.Transpose(dcUnique.Keys)
End Sub
The code tweak that worked for me was to put the Split at the end.
'Add unique data to new location
For i = 1 To UnqArray.Count
rCell(i, 1) = Split(UnqArray(i), ",")
Next
This then built up an array using data from different ranges and splitting up comma separated ones before outputting only the unique ones.