Add item to dictionary from previous dictionary (VBA) - excel

How do I do this? Here's some sample code I tried
Sub testing()
Dim n As Long
Dim dict As New Dictionary
Dim obj as MyClass
For n = 1 To 10
Set obj = New MyClass
obj.value="I am an object" 'setting obj property
dict.Add n, bcell
Next n
subDict.Add dict.Keys(1), dict.Items(1)'error here
End Sub
This throws an error:
'Run-time error 424:
Object required

Both the Item and the Key are required - that's why you were getting the 'argument not optional' error.
Now you're adding bcell which is neither declared nor instantiated. Did you mean to add obj?
Sub test()
Dim Dict As Scripting.Dictionary
Dim subDict As Scripting.Dictionary
Dim obj As MyClass
Dim n As Long
Set Dict = New Scripting.Dictionary
For n = 1 To 10
Set obj = New MyClass
obj.Value = "I'm object #" & n
Dict.Add n, obj
Next n
Set subDict = New Scripting.Dictionary
subDict.Add Dict.Keys(0), Dict.Items(0)
Debug.Print subDict.Items(0).Value
End Sub
Note that dictionairy indeces start at 0 and not 1.

Related

Assign an object to an array within a loop in VBA

I try to fill an array with objects that are created within a loop as follows. The problem is that all cells seem to have the same object in the end. The explanation might be that obj is not a local variable with respect to the loop.
Sub foo()
Dim Arr(1 To 3) As Class1
Dim i As Integer
For i = 1 To 3
Dim obj As New Class1
obj.name = i
Set Arr(i) = obj
Next
For i = 1 To 3
Debug.Print Arr(i).name
Next
End Sub
Surprisingly, the output is
3
3
3
I have also tried to remove the Set and instead have Arr(i) = obj. That results in Object variable or with block variable not set.
Your issue is the declaration of your object.
Dim foo as New bar
That is called a self-assigned declaration what makes setting a new object optional. If you call an objects member and it is not allready set it get's created (implicitSet foo = New bar). But as you allready created an instance (on first call toobj.name). that one is reused and the same reference is stored three times for the same objects-instance. That's why all elements in array return the same value as they are the same objects-instance, not three different ones.
So don't useNewin declarations, then you always need aSet fooand can check the object instance onNothing.
A second issue with your code is that assigninig an object to an array is that deleting elements from an array is error prone and not deleted references lead to not disposed, but unused objects.
The prefered storage for object(-references) is aCollection.
Sub foo()
Dim ObjCollection as Collection
Set ObjCollection = New Collection
Dim i As Integer
For i = 1 To 3
Dim obj As bar
Set obj = New bar
obj.name = i
ObjCollection.Add obj
Next
For i = 1 To 3
Debug.Print ObjCollection(i).name
Next
End Sub
This is the way:-
Sub foo()
Dim Arr(1 To 3) As Variant
Dim i As Integer
For i = 1 To 3
Set Arr(i) = Worksheets(i)
Next
For i = 1 To 3
Debug.Print Arr(i).Name
Next
End Sub
You have 2 ways to do this:
Notes: obj has not been recreated, so when you call for the next time obj in Arr (1) is still affected by the subsequent call.
First:
Sub foo()
Dim Arr(2) As Variant
Dim i As Integer
Dim obj As New Class1
For i = 0 To 2
Set obj = New Class1 '<<<-----
obj.name = i
Set Arr(i) = obj
Next
For i = 0 To 2
Debug.Print Arr(i).name
Next
End Sub
Second:
Sub foo()
Dim Arr(2) As Variant
Dim i As Integer
For i = 0 To 2
Dim obj As New Class1
obj.name = i
Set Arr(i) = obj
Set obj = Nothing <<<-----
Next
For i = 0 To 2
Debug.Print Arr(i).name
Next
End Sub
Try this, it'll save you a lot of headaches. Cheers!
Option Explicit
Sub foo()
Dim Arr(1 To 3) As New Class1 ' < good to know this version
Dim i As Long
For i = 1 To 3
With Arr(i) ' < saves you some typing
.Name = i
Debug.Print .Name
End With
Next
End Sub

Trouble with late-bound functions

Greetings I have the following code:
Private Sub makeNewReports()
Dim wkSheet As Worksheet
Set wkSheet = ActiveWorkbook.Worksheets("Grades")
Dim i As Long
Dim myMap As Dictionary
Set myMap = New Dictionary
For i = 4 To 6 'wkSheet.Range("a1").End(xlToRight).Column - 1
Dim myVals As dateValueItem
myVals.total_value = wkSheet.Cells(2, i)
myVals.items = wkSheet.Cells(1, i)
myVals.student_value = wkSheet.Cells(4, i)
myMap.Add wkSheet.Cells(3, i), myVals
Next i
End Sub
and the following code for dateValueItem
Option Explicit
Public Type dateValueItem
total_value As Long
items As String
student_value As Long
End Type
when I run the above code I get the problem
'Compile Error: Only user-defined types defined in public object modules can be coerced to or from a variant or passed to late bound functions'
I'm trying to map together 3 different values to a specific date; the dates are held in row three. Row 2 and 4 has numerical values, and row 1 has string values. The hope is to be able to organize all of these together so I can eventually connect descriptions and values to dates.
This might be the quickest way. Create a class and name it dateValueItem
Option Explicit
Public total_value As Long
Public items As String
Public student_value As Long
And change your code to
Option Explicit
Private Sub makeNewReports()
Dim wkSheet As Worksheet
Set wkSheet = ActiveWorkbook.Worksheets("Grades")
Dim i As Long
Dim myMap As Dictionary
Set myMap = New Dictionary
Dim myVals As dateValueItem
For i = 4 To 6 'wkSheet.Range("a1").End(xlToRight).Column - 1
Set myVals = New dateValueItem
myVals.total_value = wkSheet.Cells(2, i)
myVals.items = wkSheet.Cells(1, i)
myVals.student_value = wkSheet.Cells(4, i)
myMap.Add wkSheet.Cells(3, i), myVals
Next i
End Sub

dictionarys and functions: User-defined type not defined

I have typed the following code in Excel VBA:
The function should create a dictionary acording to unique values in a certain column part.
Function CreateDictForFactors(xcord As Integer, ycord As Integer, length As Integer) As Dictionary
Dim Dict As Dictionary
Set Dict = New Dictionary
Dim i As Integer
For i = 0 To length - 1
If Not Dict.Exists(Cells(xcord + i, ycord)) Then
Dict.Add Cells(xcord + i, ycord), 0
End If
Next i
Set CreateDictForFactors = Dict
End Function
Sub test2()
Dim dict1 As Dictionary
Set dict1 = CreateDictForFactors(7, 6, 12)
End Sub
I found this code as an excample for dictionaries and functions:
Sub mySub()
dim myDict as Dictionary
set myDict = myFunc()
End Sub
Function myFunc() as Dictionary
dim myDict2 as Dictionary
set myDict2 = new Dictionary
'some code that does things and adds to myDict2'
set myFunc=myDict2
End Function
However when I try to run the makro test2 it gives the error message:
User-defined type not defined
Can anyone tell where I made a mistake?
Thank you in advance
G'day,
Did you add "Microsoft Scripting Runtime" as a reference to your project?
Once you've done that, declare dict as a Scripting.Dictionary like this:
Dim dict As Scripting.Dictionary
You can create the object as follows:
Set dict = New Scripting.Dictionary
This is a good website describing the use of a dictionary:
https://excelmacromastery.com/vba-dictionary/
Hope this helps.
You can also late bind the code like this:
Function CreateDictForFactors(xcord As Integer, ycord As Integer, length As Integer) As Dictionary
Dim Dict As Object
Set Dict = CreateObject("Scripting.Dictionary")
Dim i As Integer
For i = 0 To length - 1
If Not Dict.Exists(Cells(xcord + i, ycord)) Then
Dict.Add Cells(xcord + i, ycord), 0
End If
Next i
Set CreateDictForFactors = Dict
End Function
Sub test2()
Dim dict1 As Object
Set dict1 = CreateDictForFactors(7, 6, 12)
End Sub
Note that neither method will work on a Mac.

Why is my public dictionary popping out 1004 errors?

I'm trying to establish a public dictionary to query at various points in the use of my document. But- the document appears to "forget" about the dictionary assigned? Is there a problem with my code?
Dim hedDict As Scripting.Dictionary
Public Function headDict()
On Error Resume Next
Dim i As Long
Dim z As Long
Dim x As Variant
Dim c As Variant
Dim d As Variant
Set hedDict = New Dictionary
z = Range("A1").End(xlToRight).Column
Sheets("New Item Entry").Select
Range("A2").Select
i = 1
Do While i <= z
c = Columns(i).Rows(1).Value
d = i
Call addToDict(hedDict, c, d)
i = i + 1
Loop
End Function
Function addToDict(dic, iteem, val)
dic.Add iteem, val
End Function
Sub ChckTst()
Dim x as Long
x = Cells(i, hedDict("Order UOM Price")).Value
MsgBox (x)
End Sub
The subroutine above does various other things before calling on the dictionary, such as calling a plethora of variables, assigning an array, and creating a collection. If that could interfere, please let me know.
Thank you

Extracting a Specific Variable from a Class Module in VBA to a Standard Module

All,
The following code is from Bloomberg. It is designed to extract bulk data from their servers. The code works, but I am trying to extract a specific variable generated in the class module and bring it to the Regular Module for user defined functions. Thanks for the help.
Option Explicit
Private WithEvents session As blpapicomLib2.session
Dim refdataservice As blpapicomLib2.Service
Private Sub Class_Initialize()
Set session = New blpapicomLib2.session
session.QueueEvents = True
session.Start
session.OpenService ("//blp/refdata")
Set refdataservice = session.GetService("//blp/refdata")
End Sub
Public Sub MakeRequest(sSecList As String)
Dim sFldList As Variant
Dim req As Request
Dim nRow As Long
sFldList = "CALL_SCHEDULE"
Set req = refdataservice.CreateRequest("ReferenceDataRequest") 'request type
req.GetElement("securities").AppendValue (sSecList) 'security + field as string array
req.GetElement("fields").AppendValue (sFldList) 'field as string var
Dim cid As blpapicomLib2.CorrelationId
Set cid = session.SendRequest(req)
End Sub
Public Sub session_ProcessEvent(ByVal obj As Object)
Dim eventObj As blpapicomLib2.Event
Set eventObj = obj
If Application.Ready Then
If eventObj.EventType = PARTIAL_RESPONSE Or eventObj.EventType = RESPONSE Then
Dim it As blpapicomLib2.MessageIterator
Set it = eventObj.CreateMessageIterator()
Do While it.Next()
Dim msg As Message
Set msg = it.Message
Dim Security As Element
Set Security = msg.GetElement("securityData").GetValue(0)
Sheet1.Cells(4, 4).Value = Security.GetElement("security").Value
Dim fieldArray As Element
Set fieldArray = Security.GetElement("fieldData")
Dim field As blpapicomLib2.Element
Set field = fieldArray.GetElement(0)
If field.DataType = 15 Then
Dim numBulkValues As Long
numBulkValues = field.NumValues '76
Dim index As Long
For index = 0 To numBulkValues - 1
Dim bulkElement As blpapicomLib2.Element
Set bulkElement = field.GetValue(index)
Dim numBulkElements As Integer
numBulkElements = bulkElement.NumElements '2 elements per each pt
ReDim Call_Sch(0 To numBulkValues - 1, 0 To numBulkElements - 1) As Variant
Dim ind2 As Long
For ind2 = 0 To numBulkElements - 1
Dim elem As blpapicomLib2.Element
Set elem = bulkElement.GetElement(ind2)
Call_Sch(index,ind2)=elem.Value
Sheet1.Cells(index + 4, ind2 + 5) = elem.Value
Next ind2
Next index
Else
Call_Sch(index,ind2)=field.Value
Sheet1.Cells(index + 4, ind2 + 5).Value = field.Value
End If
Loop
End If
End If
End Sub
The variable i am trying to get, specifically, is the Call_Sch. I want a function in the main module to recognize the variable. Thanks again.
It isn't necessary to declare a variable before using ReDim on it; ReDim can declare a variable. However, if you added:
Public Call_Sch() as Variant ' Insert correct data type here
then you would be able to refer to it via:
<YourClassVaraibleName>.Call_Sch

Resources