excelvbaadvanced-filter

Advanced filters is returning a single duplicate name at both the beginning and end of the created list?


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.


Solution

  • Copy Unique Values From Columns

    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
    

    EDIT

    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
    
    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