0

I am not sure what the best option is for what I'm trying to do. Currently, I'm using a 3D array to hold these values, but I am just now learning about dictionaries, classes, and collections in VBA and can't determine if any of those would be better or more useful for what I'm trying to do.

I get a new spreadsheet of data every month, and I need to loop through cells looking for a number, and replace another cell's data based on that number. I.E. (all in Col. A)

4323
4233
4123
4343
4356
3213

In column B, I need to put a corresponding country. If the first two digits are 43, the cell to the right should be "Germany" and then in col. C, "DEU". If the two numbers are 41, then the col. B cell should be "USA", and in C, "USA"...etc. etc.

Currently, I'm setting up a 3D array (psuedo code):

myArray(0,0) = 43
myArray(0,1) = "Germany"
myArray(0,2) = "DEU"
myArray(1,0) = 41
myArray(1,1) = "United States"
myArray(1,2) = "USA" 
etc. etc.

Then, I have a loop going through all the cells and replacing the information.

Would a class perhaps be better? I could then do something like create a cntry. Code, cntry.Country, cntry.CountryAbbrev and use those to refer to "43", "Germany", and "DEU"

(again, psuedo code):

num = left("A1",2) 
'then here, somehow find the num in cntry.Code list - will need to work out how
Cells("B1").Value = cntry.Country
Cells("C1").Value = cntry.CountryAbbrev

... As for Dictionaries, I think that won't work, as (AFAIK) you can only have one key per entry. So I could do the country number ("43") but set only either the Country name or Country Abbreviation - but not both....correct?

Does this question make sense? Is using a class/dictionary overkill on something like this? Would a collection be best?

Thanks for any advice/guidance!

5
  • 1
    How about a lookup to a table in Excel? Easier to maintain, I'd think. Commented Jul 2, 2015 at 17:26
  • @DougGlancy - Actually, the first method I used was a lookup table. This works fine, I just dislike having to add all the code (and actual process) of opening a file I have saved, run a lookup, then close the file. Also, I'm looking to learn more about VBA and came across dictionaries/classes and wanted to learn about them. Commented Jul 2, 2015 at 17:49
  • You can use a Dictionary keyed on country number, where the value is a 2-member array of Country and Country Abbreviation Commented Jul 2, 2015 at 18:34
  • @TimWilliams - that sounds like a good idea. How would I then refer to both parts of that 2-member array? Commented Jul 2, 2015 at 18:37
  • 1
    Something like myDict.Add "43", Array("Germany","DEU") then to get the country abbreviation it would be Debug.Print myDict("43")(1) To be honest though Doug's suggestion is the easiest to manage - you can store the lookup table on a hidden sheet in the same file as the macro code. Commented Jul 2, 2015 at 18:52

2 Answers 2

2

Class Module is the answer. It's always the answer. Code is code and there's almost nothing you can do in a class module that you can't do in a standard module. Classes are just a way to organize your code differently.

But the next question becomes how to store your data inside your class module. I use Collections out of habit, but Collection or Scripting.Dictionary are your best choices.

I'd make a class called CCountry that looks like this

Private mlCountryID As Long
Private msCode As String
Private msFullname As String
Private msAbbreviation As String

Public Property Let CountryID(ByVal lCountryID As Long): mlCountryID = lCountryID: End Property
Public Property Get CountryID() As Long: CountryID = mlCountryID: End Property
Public Property Let Code(ByVal sCode As String): msCode = sCode: End Property
Public Property Get Code() As String: Code = msCode: End Property
Public Property Let Fullname(ByVal sFullname As String): msFullname = sFullname: End Property
Public Property Get Fullname() As String: Fullname = msFullname: End Property
Public Property Let Abbreviation(ByVal sAbbreviation As String): msAbbreviation = sAbbreviation: End Property
Public Property Get Abbreviation() As String: Abbreviation = msAbbreviation: End Property

Then I'd make a class called CCountries to hold all of my CCountry instances

Private mcolCountries As Collection

Private Sub Class_Initialize()
    Set mcolCountries = New Collection
End Sub

Private Sub Class_Terminate()
    Set mcolCountries = Nothing
End Sub

Public Property Get NewEnum() As IUnknown
    Set NewEnum = mcolCountries.[_NewEnum]
End Property

Public Sub Add(clsCountry As CCountry)
    If clsCountry.CountryID = 0 Then
        clsCountry.CountryID = Me.Count + 1
    End If

    mcolCountries.Add clsCountry, CStr(clsCountry.CountryID)
End Sub

Public Property Get Country(vItem As Variant) As CCountry
    Set Country = mcolCountries.Item(vItem)
End Property

Public Property Get Count() As Long
    Count = mcolCountries.Count
End Property

You see that CCountries is merely a Collection at this point. You can read more about that NewEnum property at http://dailydoseofexcel.com/archives/2010/07/09/creating-a-parent-class/

Then I'd put all my country stuff in a Table and read that table into my class. In CCountries

Public Sub FillFromRange(rRng As Range)

    Dim vaValues As Variant
    Dim i As Long
    Dim clsCountry As CCountry

    vaValues = rRng.Value

    For i = LBound(vaValues, 1) To UBound(vaValues, 1)
        Set clsCountry = New CCountry
        With clsCountry
            .Code = vaValues(i, 1)
            .Fullname = vaValues(i, 2)
            .Abbreviation = vaValues(i, 3)
        End With
        Me.Add clsCountry
    Next i

End Sub

I'd need a way to find a country by one of its properties

Public Property Get CountryBy(ByVal sProperty As String, ByVal vValue As Variant) As CCountry

    Dim clsReturn As CCountry
    Dim clsCountry As CCountry

    For Each clsCountry In Me
        If CallByName(clsCountry, sProperty, VbGet) = vValue Then
            Set clsReturn = clsCountry
            Exit For
        End If
    Next clsCountry

    Set CountryBy = clsReturn

End Property

Then I'd run down my list of numbers and put the codes next to them

Sub FillCodes()

    Dim clsCountries As CCountries
    Dim rCell As Range
    Dim clsCountry As CCountry

    Set clsCountries = New CCountries
    clsCountries.FillFromRange Sheet1.ListObjects("tblCountries").DataBodyRange

    For Each rCell In Sheet2.Range("A3:A5").Cells
        Set clsCountry = Nothing
        Set clsCountry = clsCountries.CountryBy("Code", CStr(rCell.Value))

        If Not clsCountry Is Nothing Then
            rCell.Offset(0, 1).Value = clsCountry.Fullname
            rCell.Offset(0, 2).Value = clsCountry.Abbreviation
        End If
    Next rCell

End Sub

Other than defining where the codes I'm looping through are, I don't really need any comments. You can tell what's going on my the name of the object and the properties or methods. That's the payoff for the extra work in setting up class modules - IMO.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks so much for this! I will take some time to study it and let you know if I have any questions. Thanks again!!!
1

You can have a dictionary of objects or dictionaries.

VBA has several methods to store data:

  • a Dictionary
  • a Collection
  • an array (matrix) variable
  • an ActiveX ComboBox
  • an ActiveX ListBox
  • a Userform control ComboBox
  • a Userform control ListBox
  • a sortedlist
  • an arraylist

I suggest you to read the following article:

http://www.snb-vba.eu/VBA_Dictionary_en.html

1 Comment

Thanks for the link, I'll look through the article.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.