Using Dictionary Object in Excel VBA - excel

I am struggling to make my Dictionary object work to return economic details of selected Reference number.
e.g. I have below reference nos and corresponding values, however, not sure if I can achieve this using Dictionary object , and alternative, suggestion would be highly appreciated.
Ref No Amount Price Year
IB1232 1000 1.23 2011
IB1231 1000 3.23 2011
IB1233 1000 3.43 2011
IB1234 1000 3.43 2011
I thought would be able to achieve by forming Key and Value for reference and their corresponding details, but not been able to achieve ..

#das_weezul
There is a Dictionary object in VBA in the scripting library (you need to add that reference to use it). The Dictionary has some extra functionality, such as the ability to check if a key exists before trying to access it.
#Sky Cobb
Yes, you could do all of the above tasks with the Dictionary. The syntax will the same, except you should provide a key for every item that you add to it.

I don't know what you're referring to as Dictionary in VBA, as the data structure with the said functionality is called Collection in VBA (but maybe you coded your own Ditionary, in that case we need the code in order to be able to help you).
If I get your example right, you want to access e.g {1000,1.23,2011} via the key "IB1232". You can do this easily by creating a Collection of Collections like this:
Dim coll as new Collection
Dim data as new Collection
data.Add 1000
data.Add 1.23
data.Add 2011
coll.Add data, "IB1232"
To access your data just get the desired record (Collection) via the key
Debug.Print coll.Item("IB1232")(1) 'Prints 1000
Debug.Print coll.Item("IB1232")(2) 'Prints 1.23
Debug.Print coll.Item("IB1232")(3) 'Prints 2010
You can also use an array of Variants for the data

As mentioned before, you need to enable a reference to get the Dictionary object, but it absolutely does exist. To add the reference: Tools > References > [x] Microsoft Scripting Runtime
Public Sub test_dict()
Dim td As Object
Set td = New Dictionary
td("IB1232") = "1000 1.23 2011"
td("IB1233") = "1000 3.43 2011"
'Another way to do it, may be around for legacy support
td.Item("IB1234") = "1000 3.43 2011"
'What you probably want... a key:value dictionary where the value is a collection
Set td("IB1231") = New Collection
td("IB1231").add 1000
td("IB1231").add 3.23
td("IB1231").add 2011
'Get value by key
Debug.Print td("IB1234")
'Get a collection's value.... it's 1-indexed
Debug.Print td("IB1231")(1)
'Test if a key exists
Debug.Print td.exists("IB12345")
'See how many items there are
Debug.Print td.Count()
End Sub

Related

Trying to store user values into an array

I am trying to create an array of a user set length that users can add values to that will be saved and output on multiple sheets. I am very new to VBA so I do not know if what I am trying to do is possible but I have tried a few methods unsuccessfully.
This is the code I have so far
Sub addCost()
Dim costArray() As Variant
ReDim Preserve costArray(1 To Range("b2").Value)
For i = 1 To Range("b2").Value
costArray(i) = 0
Next i
Dim newCost As Variant
Dim costYear As Variant
newCost = InputBox("New cost amount:")
costYear = InputBox("Year new cost is active:")
costArray(costYear) = newCost
End Sub
Here is what the input tab looks like in excel
With the length of the array being the project lifespan and the add new cost activating the code, clear costs are still in progress. Is there a way for the array to store after multiple executions of the addCost sub?
Thanks!
This link Microsoft shows some methods of store values after the macro ending (in your case, sub addCost)
I think the first solution will be good for you.
Other solutions is use Access to store data (specially if you need these data over time) or a new and clean worksheet where you can store array entries in a cell (This is a very practical solution if the number of entries does not get too big)

VBscript to get total count of unique values in spreadsheet

UPDATED with questions still:
So I've used count before and haven't had issue. However I am trying to get a total for each unique value in a spreadsheet. I'm using vb script because I need this to be outside of excel for several reasons.
So if my data is like :
Bob
Bob
Ted
Ann
Ann
I'm looking for the results to be
Bob =2
Ted = 1
Ann = 2
etc...
This is what I have so far, which gets me my unique count but not a total for the unique items...
Dim objDict,item,arr,cRow, result,count
Set objDict = CreateObject("Scripting.Dictionary")
arr= .Sheets(1).Range("A2:A" & iLastRow )
For Each key In arr
If key <>"" Then
If Not objDict.Exists(key) Then objDict.Add key, Nothing
else
objDict.key("name").Item = objDict.Item() + 1
end if
End If
Next
I've updated with Marks suggestion, yet I continue to get hung up on key.
I'm not understanding how to use in this situation. From the help file Mark supplied, the example is adding a key and an item. I'm just adding keys, so what am I missing here?
Thanks for any help in this. Just pointers in the right direction are most welcome.

Is it possible to use a variant as a data source for a table?

So I have a Variant that is storing keys from a Dictionary. I need to put these values into a table but as far as I can tell the data source for a table has to be a range. Is there anyway around this? If not, is there a way to convert my variant to a range?
(Extra details about the Dict and Variant)
Both rely on imported data so there are no fixed values or even number of values, making my issue that much more complicated.
I've tried looking around for answers to this as I am at a complete loss - this is well beyond my current knowledge of vba - but what little I did find didn't seem to work.
Here's the code (only for creating the table but can provide more if needed) without any lines trying to convert the xInput. xInput is the Variant and hashTbl is the Dictionary.
ReDim xInput(0 To hashTbl.Count - 1) 'Redefine xInput as hashTbl values
For i = 0 To hashTbl.Count - 1
xInput(i) = hashTbl.Keys(i)
Next i
Set objTable = ActiveSheet.ListObjects.Add(xlSrcRange, xInput, Selection, , xlYes)
objTable.TableStyle = "TableStyleMedium2"
Of course, I want the table to be populated with the data contained in xInput but all I get is "Runtime Error - 5 Invalid Procedure Call or Argument"
Any help would be much appreciated.

Access - Loop through table and find foreign keys in a second table and Concatenate multiple fields into original table

Access - We have a table with a memo field [DESCRIPTION_OF_REQUEST].
Another table to record any date changes (for deliverables) that occur to a particular request. One to many relationship.
From a reporting point of view we are required to export (as Excel) the requests on a monthly basis and would like to have all the changes to any deliverable dates concatenated to the comments field.
[tblRequests]
RegProjID DateOfRequest DESCRIPTION_OF_REQUEST
---------- ------------- ----------------------
116 06 Oct 2015 "Stability of broken ampoule."
and
[tblDateChanges]
RegProjChangeID RegProjID DateOfDateChange UserName ReasonForChange
--------------- --------- ---------------- -------- ---------------
355 116 19 Jan 2016 dskelly "Duplicate Request from Simon Wong CPP Request already in process Original Request # 13661"
1549 116 21 Mar 2016 sdoyle This request looks like an entry error - it is logged as Trandate 200mg tablets, but refers to a broken ampoule. We received an enquiry from Francisco Gomez for information on a broken Trandate ampoule which has been logged correctly as Req ID 18540.
The output must have the two reasons for the change in the request concatenated into the DESCRIPTION_OF_REQUEST
Can we build a query that will concatenate all the ReasonForChange into one record prior to export or should this be done in Excel by exporting two queries?
As usual a simple database has grown into a valuable reporting tool and the powers that be want it to be everything to everyone.
Thank you for any suggestions you may have.
If you are okay with adding a new field to your primary table it would be pretty simple using VBA, you could do something like this:
Function updateReasonForChange()
Dim db AS DAO.Database
Dim Req AS DAO.Recordset
Dim Chg AS DAO.Recordset
Set db = currentDb()
Set Req = db.OpenRecordset("tblRequests")
Set Chg = db.OpenRecordset(SQL here to select only changes that have not previously
been added to tblRequests, use a date range would be my preference but you could also
create a yes/no field in the date changes table to mark it as processed)
Req.MoveFirst
Chg.MoveFirst
Do While Not Chg.EOF 'run though all date change records selected
Req.Seek "=" Chg![RegProjID] 'This assumes you have RegProjID indexed
If Req.NoMatch
'do nothing if no match is found, you could add some error handling here
'but if you have a parent-child relationship you should have no issue
Else
Req.Edit
Req![DESCRIPTION_OF_REQUEST] = Req![DESCRIPTION_OF_REQUEST] & " " & Chg![ReasonForChange]
Req.Update
End if
Loop
Req.Close
Chg.Close
db.Close
Set Req = Nothing
Set Chg = Nothing
Set db = Nothing
End Function
EDIT: Your field type for [DESCRIPTION_OF_REQUEST] will matter here, if it is set to max of 255 characters your may have errors due to many reasons for change being added to the same record, you may have to change that.
All this, and I would recommend a simple output select query joined on the primary key, bring in the [DateOfDateChange] and [ReasonForChange] and display the result as a pivot table vs a simple spread sheet, it will serve your purposes much better I would think.

Remove duplicates in a collection and put into array

I have a collection of Applicants. The collection has Names, University, Age, Date, etc.
I would like to create an array that just holds the unique Names from the Applicants collection.
I wanted to somehow create a new dictionary that uses the Names as keys since keys can't be duplicates:
Dim z As Variant
Dim d As Object
Set d = CreateObject("Scripting.Dictionary")
For Each z In Applicants
d(z("Names")) = 1
Next
However I do not know if this would work because I am running into errors. I want to create an array afterwards that will hold the unique keys or the Names in this case.
You need to test if the key exists before adding or you will throw an error. Additionally, you have the non-unique .Item in a Scripting.Dictionary that can store single or delimited fields from the same record.
For Each z In Applicants
if not d.exists(z("Names")) then
d.Add Key:=z("Names"), Item:=z("University") & "|" & z("Age") & "|" & z("Date")
end if
Next
I'm not sure about z("Names") but you have not provided enough information about Applicants to prove more than what your sample was using. The .Item. can be retrieved using the key and a Split function on the delimiter will create an array.

Resources