I am attempting to combine four separate list of name into a single list without showing any duplicates. The code below uses the advanced filters to first filter for unique names from each of the four list and then combine them into a single name list. It then again uses advanced filters on the newly created consolidated name list to double check for duplicates and then writes the final list of unique names.
My issue is that the final name list is showing a single duplicate name that appears at both the beginning and at the end list.
Option Explicit
Sub CreateUniqueList()
Dim lastrow As Long
ActiveSheet.Range("d:d").Clear
ActiveSheet.Range("x:x").Clear
ActiveSheet.Range("g13:g36").AdvancedFilter xlFilterCopy, , ActiveSheet.Range("D2"), True
lastrow = Cells(Rows.Count, "d").End(xlUp).Row + 1
ActiveSheet.Range("i13:i36").AdvancedFilter xlFilterCopy, , ActiveSheet.Range("d" & lastrow), True
lastrow = Cells(Rows.Count, "d").End(xlUp).Row + 1
ActiveSheet.Range("k13:k36").AdvancedFilter xlFilterCopy, , ActiveSheet.Range("d" & lastrow), True
lastrow = Cells(Rows.Count, "d").End(xlUp).Row + 1
ActiveSheet.Range("m13:m36").AdvancedFilter xlFilterCopy, , ActiveSheet.Range("d" & lastrow), True
lastrow = Cells(Rows.Count, "d").End(xlUp).Row
ActiveSheet.Range("d2:d" & lastrow).AdvancedFilter xlFilterCopy, , ActiveSheet.Range("x2"), True
ActiveSheet.Range("d:d").Clear
End Sub
I'm sure it is a simple mistake but for the life of me I can't figure it out.
AdvancedFilter
will copy the headers, so if the first row is 1, and 1 is found somewhere below, it will remain a duplicate. An idea would be to copy the range from column D
to X
right before your last AdvancedFilter action and apply a RemoveDuplicates
instead.Option Explicit
Sub CreateUniqueList()
' Source
Const sName As String = "Sheet1"
Const srgAddress As String = "G13:M36"
Dim sCols As Variant: sCols = Array(1, 3, 5, 7)
' Destination
Const dName As String = "Sheet1"
Const dfCellAddress As String = "X2"
' Workbook
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Return the values from the source range ('srg')
' in the 2D one-based source array ('sData').
Dim sws As Worksheet: Set sws = wb.Worksheets(sName)
Dim srg As Range: Set srg = sws.Range(srgAddress)
Dim sData As Variant: sData = srg.Value
' Return the unique values from the designated columns ('sCols')
' of the source array in a dictionary ('dict')
Dim dict As Object: Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Dim c As Long
For c = LBound(sCols) To UBound(sCols)
DictAddColumn dict, sData, sCols(c)
Next c
Erase sData
' Return the values from the dictionary
' in the 2D one-based one-column destination array ('dData').
Dim dData As Variant: dData = GetColumnDictKeys(dict)
Set dict = Nothing
Dim drCount As Long: drCount = UBound(dData, 1)
Dim dws As Worksheet: Set dws = wb.Worksheets(dName)
With dws.Range(dfCellAddress)
' Write the result.
.Resize(drCount).Value = dData
' Clear below.
.Resize(dws.Rows.Count - .Row - drCount + 1) _
.Offset(drCount).ClearContents
End With
MsgBox "Unique list created.", vbInformation
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Adds the unique values from a column ('sColumnIndex')
' of a 2D array ('sData') to an existing dictionary ('dDict').
' Remarks: Error values and blanks are excluded.
' Remarks: 'ByRef' indicates that the dictionary in the calling procedure
' will be modified.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Sub DictAddColumn( _
ByRef dDict As Object, _
ByVal sData As Variant, _
Optional ByVal sColumnIndex As Variant, _
Optional ByVal DoCount As Boolean = False)
Const ProcName As String = "DictAddColumn"
On Error GoTo ClearError
Dim sKey As Variant
Dim sr As Long
For sr = LBound(sData, 1) To UBound(sData, 1)
sKey = sData(sr, sColumnIndex)
If Not IsError(sKey) Then
If Len(CStr(sKey)) > 0 Then
If DoCount Then
dDict(sKey) = dDict(sKey) + 1
Else
dDict(sKey) = Empty
End If
End If
End If
Next sr
ProcExit:
Exit Sub
ClearError:
Debug.Print "'" & ProcName & "' Run-time error '" _
& Err.Number & "':" & vbLf & " " & Err.Description
Resume ProcExit
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Returns the keys from a dictionary ('sDict')
' in a 2D one-based one-column array.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function GetColumnDictKeys( _
ByVal sDict As Object) _
As Variant
Const ProcName As String = "GetColumnDictKeys"
On Error GoTo ClearError
Dim dData As Variant: ReDim dData(1 To sDict.Count, 1 To 1)
Dim sKey As Variant
Dim dr As Long
For Each sKey In sDict.Keys
dr = dr + 1
dData(dr, 1) = sKey
Next sKey
GetColumnDictKeys = dData
ProcExit:
Exit Function
ClearError:
Debug.Print "'" & ProcName & "' Run-time error '" _
& Err.Number & "':" & vbLf & " " & Err.Description
Resume ProcExit
End Function
RemoveDuplicates
.Sub CreateUniqueListCopyByAssignment()
' without helper column
Const cCount As Long = 4
Dim ws As Worksheet: Set ws = ActiveSheet ' improve!
Dim srg As Range: Set srg = ws.Range("G13:G36")
Dim rCount As Long: rCount = srg.Rows.Count
Dim drg As Range: Set drg = ws.Range("X2").Resize(rCount)
Application.ScreenUpdating = False
ws.Range("X2:X" & ws.Rows.Count).Clear
Dim c As Long
For c = 0 To cCount - 1
drg.Offset(c * rCount).Value = srg.Offset(, c * 2).Value
Next c
drg.Resize(rCount * cCount).RemoveDuplicates 1, xlNo
Application.ScreenUpdating = True
End Sub
RemoveDuplicates
near the end, mentioned at the top of this post. I think these ranges are too small to harvest the power of AdvancedFilter
.Sub CreateUniqueListQuickFix()
' with helper column
Application.ScreenUpdating = False
With ActiveSheet
Dim rCount As Long: rCount = .Rows.Count
Dim lr As Long
.Range("X2:X" & rCount).Clear
.Range("g13:g36").AdvancedFilter xlFilterCopy, , .Range("D2"), True
lr = Cells(rCount, "D").End(xlUp).Row + 1
.Range("i13:i36").AdvancedFilter xlFilterCopy, , .Range("D" & lr), True
lr = Cells(rCount, "D").End(xlUp).Row + 1
.Range("k13:k36").AdvancedFilter xlFilterCopy, , .Range("D" & lr), True
lr = Cells(rCount, "D").End(xlUp).Row + 1
.Range("m13:m36").AdvancedFilter xlFilterCopy, , .Range("D" & lr), True
lr = Cells(rCount, "D").End(xlUp).Row
.Range("D2:D" & lr).RemoveDuplicates 1, xlNo
lr = Cells(rCount, "D").End(xlUp).Row
.Range("D2:D" & lr).Copy .Range("X2")
.Range("D2:D" & lr).Clear
End With
Application.ScreenUpdating = True
End Sub