Reputation: 457
I'm trying to create a dictionary of lists. I'm used to this in python but in vba I'm having difficulties. The data is in columns A and B (I'll be using a range with end(xldown) instead of hardcoding A1:A4 this is just illustrative) and they look something like this:
A Apple
A Banana
B Carrot
B Juice
Essentially I'm wanting to create a dictionary that looks (in python format as: {A:[Apple,Bannana], B:[Carrot,Juice]}
The end result being that I'll want to paste the dictionary values in another column C that will look like this:
A Apple Apple/Banana
A Banana Apple/Banana
B Carrot Carrot/Juice
B Juice Carrot/Juice
I've been trying a nested loop through varrays but it hasn't been recognizing the relative positions of Column A and B. I was wondering what the best way to do this in VBA is?
Thanks.
Upvotes: 1
Views: 2803
Reputation: 739
As PatricK already showed, there are Dictionaries in VBA, but only through Scripting, and not as nicely intergrated into the language as in Python (God, I miss those lists and dictionaries). That method usually works, but does require the referencing of Scripting or the use of late binding, as PatricK shows.
As an alternative, you could use a Collection of classes. Define a class module and give it some variables, one of which a Collection. That way, you could loop through your collection of classes to find the index letter (A and B in this example) and extract your list of fruits from the stored class.
I find this method more flexible and scalable (you have complete control over the class module). And it is a 'native' solution, which will work on any machine, also on Mac (where referencing can be a pain sometimes).
If you want, I can elaborate with an example, but I can never be as complete as Chip Pearson on his site.
Upvotes: 1
Reputation: 6433
You can do with VBA only or mix with a UDF.
Consider originally you have (to demonstrate one of the options):
Create a module and put this in:
Option Explicit
Private lRow As Long
Private oDict As Object
Private Sub CreateDict()
Dim arrValues As Variant, oKey As Variant, oValue As Variant, i As Long
If oDict Is Nothing Then
lRow = Worksheets("Sheet2").UsedRange.Rows.Count
Set oDict = CreateObject("Scripting.Dictionary")
Else
If lRow <> Worksheets("Sheet2").UsedRange.Rows.Count Then oDict.RemoveAll ' Remove old items
End If
' Add items to the dictionary
' Load values of used range to memory
arrValues = Worksheets("Sheet2").UsedRange.Value
' Assuming the Key is on first column and Value is on next
For i = 1 To UBound(arrValues)
oKey = arrValues(i, 1)
oValue = arrValues(i, 2)
If Len(oKey) > 0 Then
If oDict.Exists(oKey) Then
' Append Value to existing key
oDict.Item(oKey) = oDict.Item(oKey) & "/" & oValue
Else
' Add Key and value
oDict.Add oKey, oValue
End If
End If
Next
End Sub
Function GetList(ByVal oRange As Range) As String
If lRow <> Worksheets("Sheet2").UsedRange.Rows.Count Then Set oDict = Nothing
If oDict Is Nothing Then CreateDict
GetList = oDict.Item(oRange.Value)
End Function
The macro above is to create the dictionary list. Then on next column, use formula to call the UDF GetList
, e.g.
Auto Fill the UDF to get the result you want:
Upvotes: 2
Reputation: 2167
Using a combination of formulas and VBA you can achieve your expected results. Starting in cell C1
and then dragging down to the end of your table place the following formula:
=stringconcat("/",IF($A:$A=A1,$B:$B,""))
This is inserted as an array formula using CTRL
+ SHIFT
+ ENTER
. Explaining the logic from the IF
, for each row in column A:A
that is equal to the value of that row ("A" in the example provided) it will extract it into an array (return if true option in the IF
). The best part of this is that you don't have to hardcode the range as we consider the whole column.
This array is then concatenated using Chip Pearsons handy function that you can find here:
http://www.cpearson.com/excel/stringconcatenation.aspx
Include the code he kindly offers into a module and you're off to the races.
Upvotes: -1