I have sample data in Excel:
Trying to get Top-3 elements (names) by Salary and Top-3 elements (names) by Revenue.
In Visual Basic (VBA) I created dictionary with Name as a Key
and nested dictionary as Item
Nested dictionary have "Salary
", "Revenue
" and "Position
" as Keys. And corresponding values as Items.
I created Dictionary as follows:
Dim MainDict As New Scripting.Dictionary
Dim NestedDict As Scripting.Dictionary
Dim rngRange As Range
Set rngRange = wsMainWorkSheet.Range("B2:E8")
Dim rowCounter As Long
For rowCounter = 1 To rngRange.Rows.Count
Set NestedDict = New Dictionary
NestedDict.Add key:="Salary", Item:=rngRange(rowCounter, 2)
NestedDict.Add key:="Revenue", Item:=rngRange(rowCounter, 3)
NestedDict.Add key:="Position", Item:=rngRange(rowCounter, 4)
Dim mainKey As String
mainKey = CStr(rngRange(rowCounter, 1))
If MainDict.Exists(mainKey) = False Then
MainDict.Add key:=mainKey, Item:=NestedDict
Else:
MainDict.Item(mainKey)("Salary") = MainDict.Item(mainKey)("Salary") + rngRange(rowCounter, 2)
MainDict.Item(mainKey)("Revenue") = MainDict.Item(mainKey)("Salary") + rngRange(rowCounter, 3)
End If
Next rowCounter
Now If I print Key, Items
in the Dictionary by the code:
Sub PrintDictionary(dict As Dictionary)
Dim key As Variant, subKey As Variant
For Each key In dict.Keys
Debug.Print vbNewLine; "Name: " & key
For Each subKey In dict(key).Keys
Debug.Print subKey & ": " & dict(key)(subKey)
Next subKey
Next key
End Sub
Result:
Name: Name1 Salary: 400 Revenue: 5000 Position: Manager
Name: Name2 Salary: 500 Revenue: 25000 Position: Associate
(first 2 shown only)
But I can't figure out the following:
How to Get Top-3 elements (names) of the list by largest salaries ("Salary" key in nested dict).
How to Get Top-3 elements (names) of the list by largest revenues ("Revenue" key in nested dict).
Is it possible to do sorting main dictionary based on nested dictionary's items in VBA without presorting data in the Excel table itself? Is it possible to sort data in such structures for further use later?
Book1.xlsm (sample data) is available on DropBox: Book1.xlsm
ADO
is a suitable method for retrieving the TOP x records.Option Explicit
Sub ADO_TOP()
Dim sSrcFile As String
Dim sSrcSht As String
Dim oRSCon As Object, sRSData As Object, sDBCon As String, sSQL As String
Dim i As Long, sSrcRng As String
sSrcFile = ThisWorkbook.FullName
sSrcSht = "Sheet1"
If Val(Application.Version) < 12 Then
sDBCon = "Provider=Microsoft.Jet.OLEDB.4.0;" & _
"Data Source=" & sSrcFile & ";" & _
"Extended Properties=""Excel 8.0;HDR=YES"";"
Else
sDBCon = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
"Data Source=" & sSrcFile & ";" & _
"Extended Properties=""Excel 12.0;HDR=YES"";"
End If
Set oRSCon = CreateObject("ADODB.Connection")
Set sRSData = CreateObject("ADODB.Recordset")
' Modify top-left cell ref of table as needed
sSrcRng = sSrcSht & "$" & Sheets(sSrcSht).Range("B1").CurrentRegion.Address(0, 0)
oRSCon.Open sDBCon
sSQL = "SELECT TOP 3 * FROM (SELECT Name,Sum(Salary) as Salary, " & _
"Sum(Revenue) as Revenue FROM [" & sSrcRng & "] GROUP BY Name) ORDER BY Salary DESC "
sRSData.Open sSQL, oRSCon, 0, 1, 1
' Write the output data to newsheet
' TOP 3 Salray
Sheets.Add
Range("A1") = "TOP 3 Salray"
For i = 0 To sRSData.Fields.Count - 1
Cells(3, i + 1).Value = sRSData.Fields(i).Name
Next i
Range("A4").CopyFromRecordset sRSData
sRSData.Close: Set sRSData = Nothing
oRSCon.Close: Set oRSCon = Nothing
End Sub
sSQL = "SELECT TOP 3 * FROM (SELECT Name,Sum(Salary) as Salary, " & _
"Sum(Revenue) as Revenue FROM [" & sSrcRng & "] GROUP BY Name) ORDER BY Revenue DESC "