What is the easiest way to take two columns of data and convert to dictionary? What is the easiest way to take two columns of data and convert to dictionary? vba vba

What is the easiest way to take two columns of data and convert to dictionary?


You would need to loop, E.g.

Function CreateDictFromColumns(sheet As String, keyCol As String, valCol As String) As Dictionary    Set CreateDictFromColumns = New Dictionary    Dim rng As Range: Set rng = Sheets(sheet).Range(keyCol & ":" & valCol)    Dim i As Long    Dim lastCol As Long '// for non-adjacent ("A:ZZ")    lastCol = rng.Columns.Count    For i = 1 To rng.Rows.Count        If (rng(i, 1).Value = "") Then Exit Function        CreateDictFromColumns.Add rng(i, 1).Value, rng(i, lastCol).Value    NextEnd Function

This breaks on the first empty key value cell.


I think it'd be best form to pass two ranges to a create dictionary function. This allows for the ranges to be completely separate, even different workbooks. It also allows for a 1D range to be mapped to a 2D range as demonstrated below.

Alternatively, you could also pass two arrays of range values. That may be cleaner for 1D ranges, but would result in slightly more code for 2D mapping. Notice that range elements can be looped through left to right top to bottom by index. You can use Application.Transpose(Range("A1:A5")) to effectively run top to bottom left to right.

Jagged Mapping

Sub Test()    RangeToDict Sheets(1).Range("A1:A5"), Sheets(2).Range("C1:E2")End SubFunction RangeToDict(ByVal KeyRng As Range, ByVal ValRng As Range) As Dictionary    Set RangeToDict = New Dictionary    For Each r In KeyRng        vi = vi + 1        'It may not be advisable to handle empty key values this way        'The handling of empty values and #N/A/Error values         'Depends on your exact usage        If r.Value2 <> "" Then            RangeToDict.Add r.Value2, ValRng(vi)            Debug.Print r.Value2 & ", " & ValRng(vi)        End If    NextEnd Function

enter image description here

Side-By-Side (As Range)

If your target range is a single 2 column range side by side, you can simplify to passing a single range as shown below. Consequently, this also works for mapping every other element in a 1 dimensional range.

Sub Test()    RangeToDict2 Range("A1:B5")End SubFunction RangeToDict2(ByVal R As Range) As Dictionary    Set RangeToDict2 = New Dictionary    i = 1    Do Until i >= (R.Rows.Count * R.Columns.Count)        RangeToDict2.Add R(i), R(i + 1)        Debug.Print R(i) & ", " & R(i + 1)        i = i + 2    LoopEnd Function

enter image description here

Two Columns (As Array)

Lastly, as an example of passing arrays as arguments, you could do something like the following. However, the following code will only work given the OP's specific scenario of mapping two columns. As is, it won't handle mapping rows or alternating elements.

Sub Test()    Dim Keys() As Variant: Keys = Range("E1:I1").Value2    Dim Values() As Variant: Values = Range("E3:I3").Value2    RangeToDict Keys, ValuesEnd SubFunction RangeToDict(Keys() As Variant, Values() As Variant) As Dictionary    Set RangeToDict = New Dictionary    For i = 1 To UBound(Keys)        RangeToDict.Add Keys(i, 1), Values(i, 1)        Debug.Print Keys(i, 1) & ", " & Values(i, 1)    NextEnd Function

Use of Named Ranges

It may be convenient to used named ranges, in which case you can pass a Range as an argument likes this...

Sub Test()    RangeToDict Names("Keys").RefersToRange, Names("Values").RefersToRangeEnd Sub


The best approach to take, is to populate a variant array with the data from the worksheet. You can then loop through the array, assigning the elements of the first array column as the dictionary key; the elements of the second array column can then be used as the value.

The lrow function is used to find the last populated row from column A - allowing the code to create a dynamically sized array and dictionary.

To enable use of dictionaries within VBA, you will need to go to Tools -> References and then enable Microsoft Scripting Runtime.

Sub createDictionary()    Dim dict As Scripting.Dictionary    Dim arrData() As Variant    Dim i as Long    arrData = Range("A1", Cells(lrow(1), 2))    set dict = new Scripting.Dictionary            For i = LBound(arrData, 1) To UBound(arrData, 1)        dict(arrData(i, 1)) = arrData(i, 2)    Next iEnd SubFunction lrow(ByVal colNum As Long) As Long    lrow = Cells(Rows.Count, 1).End(xlUp).RowEnd Function