Select the first filtered cell then move onto the next filtered cell down - excel

I have an Excel spreadsheet that has contact details, for example:
A B C D E
1 Select who you would to like to email: * Drop down list *
2 Name: Company: Role: Email Address1: Email Address2:
3 Michael Jackson Jackson 5 Singer MJ#J5.com Michael#J5.com
4 Brian May Queen Guitarist BM#Queen.com Brian#Queen.com
5 Kurt Cobain Nirvana Singer KC#Nirvana.com Kurt#Nirvana.com
6 Freddie Mercury Queen Singer FM#Queen.co.uk Freddie#Queen.com
7 Pat Smear Nirvana Guitarist PS#Foo.com Pat#Foo.com
A user selects an email address using the drop down list in D1 then runs a macro that gets the email addreses in that column.
The problem is when a user applies a filter, say all guitarists, it will select the first filtered row (C4) and then go to the next row rather than the next filtered row, so it would go to C5.
This is an adaption of the code:
Sub SendEmail()
Dim objOutlook As Object
Dim objMail As Object
Dim RowsCount As Integer
Dim Index As Integer
Dim Recipients As String
Dim Category As String
Dim CellReference As Integer
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
RowsCount = ActiveSheet.AutoFilter.Range.Columns(1).SpecialCells(xlCellTypeVisible).Cells.Count - 1
Category = Range("D1")
Dim RowLimit As String
If Category = "Email Address1" Then
CellReference = 4
ElseIf Category = "Email Address2" Then
CellReference = 5
End If
Index = 0
While Index < RowsCount
Set EmailAdrs = ActiveSheet.AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Cells(1, CellReference).Offset(0 + Index, 0)
Recipients = Recipients & EmailAdrs.Value & ";"
Index = Index + 1
Wend
With objMail
.To = Recipients
.Subject = "This is the subject"
.Display
End With
Set objOutlook = Nothing
Set objMail = Nothing
End Sub
I tried looping through rows that are hidden:
While Index < RowsCount
Do While Rows(ActiveCell.Row).Hidden = True
'ActiveCell.Offset(1).Select
Set EmailAdrs = ActiveSheet.AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).Cells(1, CellReference).Offset(0 + Index, 0)
Recipients = Recipients & EmailAdrs.Value & ";"
Index = Index + 1
ActiveCell = ActiveCell.Offset(0 + Index, 0).Select
Loop
Wend
I tried going through only cells that are visible.
I tried ideas from VBA Go to the next filtered cell:
If ActiveSheet.FilterMode = True Then
With ActiveSheet.AutoFilter.Range
For Each a In .Offset(1).Resize(.Rows.Count).SpecialCells(xlCellTypeVisible).Areas
Recipients = Recipients & a(1, CellReference) & ";"
Next
End With
MsgBox Replace(Recipients, ";;", vbNullString)
End If
And:
Dim Rng As Range
If Category = Range("S2") Then
CellReference = 10
'Set your range
Set Rng = Range("A1:B2")
ElseIf Category = Range("S3") Then
CellReference = 14
'Set your range
Set Rng = Range("C1:D2")
ElseIf Category = Range("S4") Then
CellReference = 18
'Set your range
Set Rng = Range("F1:G2")
ElseIf Category = Range("S5") Then
CellReference = 16
'Set your range
Set Rng = Range("H1:J2")
End If
For Each mCell In ThisWorkbook.Sheets("YourSheetName").Range(Rng).SpecialCells(xlCellTypeVisible)
'Get cell address
mAddr = mCell.Address
'Get the address of the cell on the column you need
NewCellAddr = mCell.Offset(0, ColumnsOffset).Address
'Do everything you need
Next mCell

Try this code:
Sub SendEmail()
Dim objOutlook As Object
Dim objMail As Object
'Dim RowsCount As Integer
'Dim Index As Integer
Dim Recipients As String
Dim Category As String
Dim CellReference As Integer
Dim RowLimit As String
'New variables.
Dim firstRow As Long
Dim lastRow As Long
Dim cell As Excel.Range
Dim row As Long
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
Category = Range("D1")
If Category = "Email Address1" Then
CellReference = 4
ElseIf Category = "Email Address2" Then
CellReference = 5
End If
With ActiveSheet
'Find the first and last index of the visible range.
firstRow = .AutoFilter.Range.Offset(1).SpecialCells(xlCellTypeVisible).row
lastRow = .Cells(.Rows.Count, 1).End(xlUp).row
'Iterate through all the rows between [firstRow] and [lastRow] established before.
'Some of those rows are hidden, but we will check it inside this loop.
For row = firstRow To lastRow
Set cell = .Cells(row, CellReference)
'We are checking here if this row is hidden or visible.
'Note that we cannot check the value of property Hidden of a single cell,
'since it will generate Run-time error '1004' because a single cell cannot be
'hidden/visible - only a whole row/column can be hidden/visible.
'That is why we need to refer to its .EntireRow property first and after that we
'can check its .Hidden property.
If Not cell.EntireRow.Hidden Then
'If the row where [cell] is placed is not hidden, we append the value of [cell]
'to variable Recipients.
Recipients = Recipients & cell.Value & ";"
End If
Next row
End With
With objMail
.To = Recipients
.Subject = "This is the subject"
.Display
End With
Set objOutlook = Nothing
Set objMail = Nothing
End Sub

I believe the Hidden property of a range is what you want. The following code worked for me:
Dim row As Range
For Each row In Range("MyTable").Rows
If not row.EntireRow.Hidden Then
''' DO STUFF '''
End If
Next
I have always found that using a For Each loop is a much cleaner way to iterate through data in an excel sheet. "MyTable" was the name I gave to the range of interest but if you prefer you can just enter a the limits of the range like Range("A1:D4"). Though I think it is a better practice to use named ranges as it makes your code more readable.
EDIT: To address your comment...
If you insert a row into the middle of a named range the limits of the range automatically expand. Though if your table is going to be the only data in the worksheet you can also use the UsedRange property of a worksheet object. For instance:
Dim row As Range
For Each row In Worksheets("MySheet").UsedRange.Rows
If not row.EntireRow.Hidden Then
''' DO STUFF '''
End If
Next
If all you have is the first row of the table you can expand this range to the full table using:
dim FirstRow as Range
dim LastRow as Range
dim myTable as Range
set FirstRow = Range("A1:B1")
set LastRow = FirstRow.End(xlDown)
set myTable = Range(FirstRow, LastRow)
And then use the same For Each loop as before. Hope this helps!

For any interested in this solution, i realized that it is much more faster to test the logic of the filter in the cell value, instead of checking if the filter has the column hidden or not (in sheets with more than 10.000 rows), hence not requiring to select an entire row each time, just a single cell.
Of course, you need to know beforehand the expression for the filter, which is not dealt in this code.
For example if the filter test values less than 0.5, it is better to try:
Range("U1").Select 'The column where the filter is being applied
ActiveCell.Offset(1, 0).Select
Do Until CDbl(ActiveCell.Formula) < 0.5 'The condition applied in the filter
ActiveCell.Offset(1, 0).Select
Loop

Related

Copying filtered cells to powerpoint table

Im relatively new to VBA. Im currently trying to run a code that copies filtered visible cells into powerpoint as a table. The dataset is rather huge and will continue to grow. How do I make the code dynamic and format the table that's being pasted into powerpoint?
Im getting an error Run time error '-2147188160 (80048240)': Shapes(unknown member) : Integer out of range. 2795 is not in the valid range of 1 to 75"
I would also like the data set to be formatted whereby the first and second column thats copied from the excel sheet gets transposed as the column headers in ppt.
The table looks like this in excel:
Product Code
Product Name
Keyword
Country
Status
Description
123456
Kobe Chicken
Chicken
Japan
Imported
NIL
643734
Hanwook Beef
Beef
Korea
Exported
NIL
The format i'd like in ppt:
123456 Kobe Chicken
643734 Hanwook Beef
(If the products list go on the products would be added via columns)
Country
Japan
Korea
NIL
Status
Imported
Exported
NIL
Description
NIL
NIL
Below is my code:
Also, is there anyway I can get the user to select from the dropdown menu of keyword to set the filtering criterea rather than entering it as a userinput for the code to filter out cells that match the criterea?
Sub Export_Range()
Dim userin As Variant
Dim userin2 As Variant
Dim pp As New PowerPoint.Application
Dim ppt As PowerPoint.Presentation
Dim sld As PowerPoint.Slide
Dim shpTable As PowerPoint.Shape
Dim i As Long, j As Long
Dim rng As Excel.Range
Dim sht As Excel.Worksheet
'To set range
userin = InputBox("Please enter the product you'd like to filter by: ")
userin2 = InputBox("Yes or No?: ")
set rng = Range("B$16:$AG$2810").Select
Selection.AutoFilter
ActiveSheet.Range("$B$16:$AG$2810").AutoFilter Field:=3, Criteria1:=userin
ActiveSheet.Range("$B$16:$AG$2810").AutoFilter Field:=4, Criteria1:=userin2
'This hides columns that are not needed in copying to ppt
Range("E16").EntireColumn.Hidden = True
Range("G16").EntireColumn.Hidden = True
Range("H16").EntireColumn.Hidden = True
Range("J16").EntireColumn.Hidden = True
Range("M16").EntireColumn.Hidden = True
Range("O16").EntireColumn.Hidden = True
Range("P16").EntireColumn.Hidden = True
Range("Q16").EntireColumn.Hidden = True
'Creates new ppt, and adds selected info into table
pp.Visible = True
If pp.Presentations.Count = 0 Then
Set ppt = pp.Presentations.Add
Else
Set ppt = pp.ActivePresentation
End If
Set sld = ppt.Slides.Add(1, ppLayoutTitleOnly)
Set shpTable = sld.Shapes.AddTable(rng.Rows.Count, rng.Columns.Count)
For i = 1 To rng.Rows.Count
For j = 1 To rng.Columns.Count
shpTable.Table.Cell(i, j).Shape.TextFrame.TextRange.Text = _
rng.Cells(i, j).Text
Next
Next
For i = 1 To rng.Rows.Count
For j = 1 To rng.Columns.Count
If (rng.Cells(i, j).MergeArea.Cells.Count > 1) And _
(rng.Cells(i, j).Text <> "") Then
shpTable.Table.Cell(i, j).Merge _
shpTable.Table.Cell(i + rng.Cells(i, j).MergeArea.Rows.Count - 1, _
j + rng.Cells(i, j).MergeArea.Columns.Count - 1)
End If
Next
Next
sld.Shapes.Title.TextFrame.TextRange.Text = _
rng.Worksheet.Name & " - " & rng.Address
End Sub
Here's an example of how to do this. I'm not sure if you simplfied your actual use case but I used this table for testing:
End Result:
Code:
Sub Tester()
'Add project reference to `Microsoft PowerPoint xx.x Object Library`
Dim loProds As ListObject, rngVis As Range, colKeyWord As ListColumn
Dim c As Range, rw As Range, visCount As Long, col As Long
Dim ppApp As PowerPoint.Application, ppPres As PowerPoint.Presentation
Dim ppSlide As PowerPoint.Slide, pptable As PowerPoint.Table
Dim indxProdCode As Long, indxProdName As Long
Dim indxCountry As Long, indxStatus As Long, indxDescr As Long
'info is in listobject "Products" on worksheet "Listing"
Set loProds = ThisWorkbook.Worksheets("Listing").ListObjects("Products")
'filter on Keyword = "Beef"
loProds.ShowAutoFilter = True
Set colKeyWord = loProds.ListColumns("Keyword")
loProds.Range.AutoFilter Field:=colKeyWord.Index, Criteria1:="Beef"
'get visible cells in keyword column
On Error Resume Next 'ignore error if no visible cells
Set rngVis = colKeyWord.DataBodyRange.SpecialCells(xlCellTypeVisible)
On Error GoTo 0 'stop ignoring errors
If rngVis Is Nothing Then 'no rows left after filtering?
MsgBox "No rows visible after applying filter...", vbExclamation
Exit Sub
End If
visCount = rngVis.Cells.Count 'how many visible rows left?
'start PPT, add a new presentation, and put a table on slide 1
Set ppApp = New PowerPoint.Application
ppApp.Visible = True
Set ppPres = ppApp.Presentations.Add()
Set ppSlide = ppPres.Slides.Add(1, ppLayoutTitleOnly)
Set pptable = ppSlide.Shapes.AddTable(4, visCount + 1).Table
SetText pptable.cell(2, 1), "Country" 'fixed row headers in column 1
SetText pptable.cell(3, 1), "Status"
SetText pptable.cell(4, 1), "Description"
'find the column indexes of the content we want to extract from `loProds`
indxProdCode = loProds.ListColumns("Product Code").Index
indxProdName = loProds.ListColumns("Product Name").Index
indxCountry = loProds.ListColumns("Country").Index
indxStatus = loProds.ListColumns("Status").Index
indxDescr = loProds.ListColumns("Description").Index
col = 1
'loop over each visible row and populate a new column in the table
For Each c In rngVis.Cells
Set rw = Application.Intersect(c.EntireRow, loProds.DataBodyRange) 'the table row for this cell
col = col + 1 'next ppt table column
SetText pptable.cell(1, col), rw.Cells(indxProdCode).Value & " " & rw.Cells(indxProdName).Value
SetText pptable.cell(2, col), rw.Cells(indxCountry).Value
SetText pptable.cell(3, col), rw.Cells(indxStatus).Value
SetText pptable.cell(4, col), rw.Cells(indxDescr).Value
Next c
End Sub
'helper method for setting table cell text
Sub SetText(cell As PowerPoint.cell, v)
cell.Shape.TextFrame.TextRange.Text = v
End Sub

Reference a range dynamically

I have this list
I want to first find familiyX and then go down to mum or dad side and then save the adresses listed below in the variable sTo.
Sub findAndStore()
Dim EmailRng As Range, cl As Range
Dim sTo As String, fam As String
fam = "family2"
Set EmailRng = Worksheets("sheet2").Range("D3:D" & Worksheets("sheet2").Cells(Worksheets("sheet2").Rows.Count, "D").End(xlUp).Row)
For Each cl In EmailRng
sTo = sTo & ";" & cl.Value
Next
End Sub
The range is hardcoded. How can I make it dynamic based on that value fam holds?
Do you actually need a code to do it ?
I would recommend to create a new sheet, where the data are fields by column and records per row, than create a pivot table and get the information you need.
However for sake of VBA training
Sub findAndStore(family_name As String)
' find the family column
Dim family_column As Integer, mum_column As Integer, dad_column As Integer
family_column = ActiveSheet.Range("1:1").Find(family_name).Column
' get values
Dim collected_addresses As String
Dim addresses_collection As Variant
Set addresses_collection = New Collection
For column_offset = 0 To 1 'mum and dad column
current_row = 3 'start on a third row under dad/mum header
Do
cell_value = ActiveSheet.Cells(current_row, family_column + column_offset).Value
current_row = current_row + 1 'move to next row
If cell_value <> "" Then addresses_collection.Add cell_value
Loop Until cell_value = ""
Next column_offset ' next column
For Each s In addresses_collection
collected_addresses = collected_addresses & s & ";"
Next s
Debug.Print collected_addresses
End Sub

Reconciling Columns VBA

I'm looking to create a reconciliation sub which will find a value in Spreadsheet A, Column A and return the corresponding value in Column B i.e. Column A = ID123; Column B = HELLO. The procedure will then find the same value in Spreadsheet B, Column A (in this example, ID123) and return the value in Column B. So ideally, I would like these 2 values to be side by side so that I can do a comparison. All I have so far is code that will return values from Column A but I am unable to return Column B. This is essentially a VLookup, but Vlookups have proven to be very consuming in VBA:
Sub findCell()
Dim ETLCell As String
Dim mifidCell As String
Dim last_row_A As Long
Dim last_row_B As Long
last_row_A = Worksheets("Spreadsheet A").UsedRange.Rows.Count
last_row_B = Worksheets("Spreadsheet B").UsedRange.Rows.Count
'Loop which returns the TRN beside each column
For i = 2 To last_row_A
ETLCell = Worksheets("Spreadsheet B").Columns("B:B").Find(What:=Worksheets("Spreadsheet A").Cells(i, 1).Value)
mifidCell = Worksheets("Spreadsheet A").Cells(i, 1).Value
Worksheets("Reconciliation").Cells(i, 1).Value = ETLCell
If ETLCell Is Nothing Then
ETLCell = "BLANK"
Worksheets("Reconciliation").Cells(i, 2).Value = "False"
Else
Worksheets("Reconciliation").Cells(i, 2).Value = "True"
End If
Next i
End Sub
I took a different approach than the one that you took to solve this issue. I tried embedding comments into the code to describe what is happening. Try reviewing it and see if you can incorporate it into your workbook, and write back with questions.
I stored the values from sheet B into a dictionary object for efficient lookup. This type of object holds a unique key, and a corresponding value. Then, I can loop over the Keys in sheet A, looking for them in sheet B, and then adding the values to the reconciliation.
Sub AnalyzeReconciliation()
Dim sht1 As Worksheet
Dim sht2 As Worksheet
Dim shtRecon As Worksheet
Dim rng1 As Range
Dim rng2 As Range
Dim cel As Range
Dim oDict As Object
Dim reconRow As Long
Set sht1 = Worksheets("Worksheet A")
Set sht2 = Worksheets("Worksheet B")
Set shtRecon = Worksheets("Reconciliation")
'I don't like using UsedRange. I find it to be unreliable
'Define the columns that you need, and find the last row
'using a method call similar to below
Set rng1 = sht1.Range("A2:B" & sht1.Range("A" & sht1.Rows.Count).End(xlUp).Row)
Set rng2 = sht2.Range("A2:B" & sht2.Range("A" & sht2.Rows.Count).End(xlUp).Row)
'Get a dictionary object holding unique values from sheet 2
'In my case, column A holds the Id, and column B holds the value
Set oDict = GetDictionary(rng2, 1, 2)
reconRow = 0
'Loop over each cel in sheet 1, column 1
'Look for the value in column 1 in the sheet 2 dictionary
'object, and then reconcile
For Each cel In Intersect(rng1, sht1.Columns(1))
'Get the next avail row in reconciliation sheet
reconRow = reconRow + 1
shtRecon.Range("A" & reconRow).Value = cel.Value
'Recon column B holds value from sheet 1, column B
shtRecon.Range("B" & reconRow).Value = cel.Offset(, 1).Value
'If Id is found in Sheet B dictionary, then take the value
'otherwise, write "blank" in column C
If oDict.exists(cel.Value) Then
shtRecon.Range("C" & reconRow).Value = oDict(cel.Value)
Else
shtRecon.Range("C" & reconRow).Value = "BLANK"
End If
Next cel
End Sub
'Function stores a range into a dictionary
'Param inputRange takes a range to be stored
'Param idColumn takes the column of the range to be used as the ID
' e.g. if idColumn = 2, and inputRange("C1:F10"), then column D
' is used for ID
'Param valueColumn points to the column in range used for the value
Function GetDictionary(inputRange As Range, idColumn As Long, valueColumn As Long) As Object
Dim oDict As Object
Dim sht As Worksheet
Dim cel As Range
Set oDict = CreateObject("Scripting.Dictionary")
Set sht = inputRange.Parent
For Each cel In Intersect(inputRange, inputRange.Columns(idColumn))
If Not oDict.exists(cel.Value) Then
oDict.Add cel.Value, sht.Cells(cel.Row, valueColumn).Value
End If
Next cel
Set GetDictionary = oDict
End Function

Why does this VBA Loop to find empty cell delete header row value?

I have a workbook where each branch office has it's own tab. Each tab has row headers of available dates for interviews, and the column headers for the available times. It is screencapped below:
From there I'm using a user form to collect the branch name from a dropdown (populated by looping through names of the sheets), the available dates (getting the days on the identified sheet), then the blank times for the given dates.
For some reason, every time a date is selected, it's setting the date cell to "" or blank. Can anyone verify my syntax if right? I can't tell where it might be setting it to blank... Thanks!
Option Explicit
Public Sub UserForm_Initialize()Dim sht As Worksheet
'clear form
BranchBox.Value = ""
DateBox.Value = ""
TimeBox.Value = ""
'populate sheet names from each branch
For Each sht In ActiveWorkbook.Sheets
Me.BranchBox.AddItem sht.Name
Next sht
End Sub
Public Sub BranchBox_Change()
'populate dates
Me.DateBox.List = Worksheets(BranchBox.Value).Range("A2:A31").Value
End Sub
Public Sub DateBox_Change()
Dim dateSel As String
Dim branch As String
Dim sht As Worksheet
Dim cel As Range
Dim matchingHeader As Range
branch = BranchBox.Value
Set sht = ActiveWorkbook.Worksheets(branch)
dateSel = DateBox.Value
'Get Row to scan
Dim i As Long, rowOff As Long
For i = 2 To sht.Rows.Count
Set cel = sht.Cells(i, 1)
If cel.Value = dateSel Then
rowOff = i
Exit For
End If
Next i
'Scan selected row for blank cells
Dim cnt As Integer
For i = 2 To sht.Columns.Count
cel = sht.Cells(rowOff, i)
If CStr(cel.Value) = "" Then
Set matchingHeader = sht.Cells(1, i)
TimeBox.AddItem matchingHeader.Value
End If
Next i
Me.TimeBox.AddItem ("No Appointments Available")
End Sub
Your line
cel = sht.Cells(rowOff, i)
is implicitly
cel.Value = sht.Cells(rowOff, i).Value
I believe you intended the line to be
Set cel = sht.Cells(rowOff, i)

Convert list of items in an Excel Table to comma-separated string

I have a table in Excel (Table1) that has these column headings: employee name, state licensed, and license status. A sample of the table would be:
John Adams NY Active
John Adams PA Active
John Adams NJ Inactive
Ralph Ames MS Active
Ed Turner MS Pending
I want to set up a summary tab that has one row per employee with a column for active licenses, pending licenses, and inactive licenses, and those cells would display a comma-separated list of the appropriate state codes. For example:
Name Active Pending Inactive
John Adams NY, PA NJ
Ralph Ames MS
Ed Turner MS
I'm just curious about the best way to get to this custom list. I wrote the function below which seems to work fine, and it runs faster than I expected, but it just seems inefficient because it loops through the entire table every time, and I've pasted formulas referencing this function to a few hundred cells:
Function comma_state_list(the_name As String, the_status As String) As String
Dim ws As Worksheet
Dim oLo As ListObject
Dim oCol As ListColumns
Set ws = Worksheets("State Licenses")
Set oLo = ws.ListObjects("Table1")
Set oCol = oLo.ListColumns
For i = 1 To oLo.ListRows.Count
If oLo.Range(i, 1).Value = the_name And oLo.Range(i, 3) = the_status Then
comma_state_list = comma_state_list & oLo.Range(i, 4) & ", "
End If
Next i
If Len(comma_state_list) = 0 Then
comma_state_list = ""
Else
comma_state_list = Left(comma_state_list, Len(comma_state_list) - 2)
End If
End Function
Is there a way to maybe use VBA to run a SQL-like query against the table so I'm just looping through the SQL result instead of the entire table every time? I was thinking this would help to alphabetize the summary list too. Or maybe there's some other better way I'm not thinking of.
OK, so here is an example using Scripting Dictionaries.
I have this table on one worksheet:
And the output should produce a new worksheet with summary data like:
I tried to document it pretty thoroughly but let me know if you have any questions about it.
Option Explicit
Sub Test()
Dim wsCurr As Worksheet: Set wsCurr = ActiveSheet
Dim wsNew As Worksheet 'output container'
Dim rowNum As Long 'row number for output'
'Scripting dictionaries:'
Dim inactiveDict As Object
Dim activeDict As Object
Dim key As Variant
'Table variables'
Dim rng As Range 'table of data'
Dim r As Long 'row iterator for the table range.'
'information about each employee/row'
Dim empName As String
Dim state As String
Dim status As String
'Create our dictionaries:'
Set activeDict = Nothing
Set inactiveDict = Nothing
Set activeDict = CreateObject("Scripting.Dictionary")
Set inactiveDict = CreateObject("Scripting.Dictionary")
Set rng = Range("A1:C6") 'better to set this dynamically, this is just an example'
For r = 2 To rng.Rows.Count
empName = rng(r, 1).Value
state = rng(r, 2).Value
status = rng(r, 3).Value
Select Case UCase(status)
Case "ACTIVE"
AddItemToDict activeDict, empName, state
Case "INACTIVE"
AddItemToDict inactiveDict, empName, state
End Select
Next
'Add a new worksheet with summary data'
Set wsNew = Sheets.Add(After:=wsCurr)
With wsNew
.Cells(1, 1).Value = "Name"
.Cells(1, 2).Value = "Active"
.Cells(1, 3).Value = "Inactive"
rowNum = 2
'Create the initial table with Active licenses'
For Each key In activeDict
.Cells(rowNum, 1).Value = key
.Cells(rowNum, 2).Value = activeDict(key)
rowNum = rowNum + 1
Next
'Now, go over this list with inactive licenses'
For Each key In inactiveDict
If activeDict.Exists(key) Then
rowNum = Application.Match(key, .Range("A:A"), False)
Else:
rowNum = Application.WorksheetFunction.CountA(wsNew.Range("A:A")) + 1
.Cells(rowNum, 1).Value = key
End If
.Cells(rowNum, 3).Value = inactiveDict(key)
Next
End With
'Cleanup:
Set activeDict = Nothing
Set inactiveDict = Nothing
End Sub
Sub AddItemToDict(dict As Object, empName As String, state As String)
'since we will use the same methods on both dictionary objects, '
' it would be best to subroutine this action:'
Dim key As Variant
'check to see if this employee already exists'
If UBound(dict.Keys) = -1 Then
dict.Add empName, state
Else:
If Not dict.Exists(empName) Then
'If IsError(Application.Match(empName, dictKeys, False)) Then
'employee doesn't exist, so add to the dict'
dict.Add empName, state
Else:
'employee does exist, so update the list:'
'concatenate the state list'
state = dict(empName) & ", " & state
'remove the dictionary entry'
dict.Remove empName
'add the updated dictionary entry'
dict.Add empName, state
End If
End If
End Sub

Resources