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.
Related
I previously used the following code -
Dim HSArr(2 To 250) As Variant
Dim HSVal As Long
For HSVal = LBound(HSArr) To UBound(HSArr)
HSArr(HSVal) = Cells(HSVal, 1) & " " & Cells(HSVal, 2)
Next HSVal
It was an array that would concatenate column A and B, then the array would be output onto the worksheet in "P2:P250".
Sub SumData()
Const dFormula As String _
= "=IFERROR(SUMPRODUCT(--(P$2:P$250=I2),D$2:D$250,F$2:F$250),"""")"
With ThisWorkbook.Worksheets("Sheet1").Range("K2:K250")
.Formula = dFormula
.Value = .Value
End With
End Sub
This code does what I want to an extent but requires "P2:P250" to contain the array output, but I don't want to output anything onto the worksheet.
There's a piece of information that I do not understand here, how I can introduce those values from the array into the SUMPRODUCT (instead of "P2:P250"), even if its not by methods of array, as AFAIK I can't use that as a range without it being on the worksheet itself. Any idea?
Building an array with VBA then trying to use it with a formula in a worksheet without placing that information into a worksheet generally wouldn't work, however here you can use the source data in the formula instead:
=IFERROR(SUMPRODUCT(--(A$2:A$250&" "&B$2:B$250=I2),D$2:D$250,F$2:F$250),"""")
I want to use an array of dictionaries to store all the content of an Excel workbook to later process it and make operations in memory.
I have defined that the first row of the Excel workbook is the key and the rest of rows are content. As I have one key for many values, I need to store them in a different container (this would be the array).
A sample of the content
Code Name Surname
1 a b
2 c d
The code:
For Each rcell In ws.UsedRange.Cells
If rcell.Row > 1 Then
ReDim Preserve aRows(rcell.Row - 2)
'Set aRows(rcell.Row - 2) = CreateObject("scripting.dictionary")
Set pInfo = New Scripting.Dictionary
pInfo.Add Key:=Cells(1, rcell.Column).Value, Item:=rcell.Value
'aRows(rcell.Row - 2).Add Key:=Cells(1, rcell.Column).Value, Item:=rcell.Value
Set aRows(rcell.Row - 2) = pInfo
End If
Next rcell
This code creates an array of dictionaries.
When I try to access the data I get an error.
I know that at least it is storing values because when I use:
debug.print(ubound(aRows))
I am getting the value (1) in this case.
I tried accessing the content with
for each row in aRows
debug.print(row.key)
next row
However, this is not accepted. How do I access the data?
An alternative or something more simple would be great.
May be this?
Dim d, k
For Each d in aRows
For Each k in d.keys
Debug.Print k, d(k),
Next
Debug.Print vbCrLf
Next
you could use
Dim myRow as Variant, key as variant
For Each myRow In aRows
With myRow
For Each key In .Keys
Debug.Print key, .Item(key)
Next
End With
Next
I am trying to avoid the use of loops for populating arrays since they take a lot of time when managing a lot of data.
Apparently as well, that is possible and easy in VBA but often results in problems.
Here is the code:
sub populate()
'put the whole column in an array
Dim AppArray() As Variant
Dim AppRange As Range
'calculate the last row of the column 1 of sheets
Dim LstRow As Integer
LstRow = Sheets("whole").Cells(Sheets("whole").Rows.Count, "A").End(xlUp).row
'here I calculate the range that I want to pass to the array
Set AppRange = Sheets("whole").Range(Cells(1, 1), Cells(LstRow, 1))
MsgBox ("apprange " & AppRange.Address)
'i dont know if I need to redim or not
ReDim AppArray(1 To LstRow)
'here comes the point. populate the array with the values of the range
AppArray = AppRange.Value
End Sub
This does not work. I also tried application.tranpose(AppRange.Value).
I used:
For i = 1 To LstRow
Debug.Print AppArray(i)
Next
and an error appears, so somehow there is no AppArray(1).
I would be very happy if you can comment on that. More than just arranging the code suggest even other pages (links) to populate arrays with values of ranges when these ranges are not known in advance.
If the case is that looping is very time consuming and that arrays can be populated straight away, I don't understand why 99% of the pages referring to arrays use a loop (or nested loop) to populate an array.
I found the answer.
dim myRange as range
dim myArray() as variant
myRange = range(cells(2,3),cells(10,15))
redeem myArray(1 to 20,1 to 20)
myArray=myRange
It's always much faster to work with variables and arrays than with cells values.
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
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.