Bob Mackenzie
Bob Mackenzie

Reputation: 71

Including duplicates

My code finds all the values in (Column A, Sheet 1) that match with the values in (Column A, sheet 2). Then, it copies the entire row of the matched value to a new sheet.

My problem is that sometimes, right below a 'matching' value in sheet1 will be a duplicate matching value. Currently my code is skipping, and not copying these rows over to the new sheet.

Thanks.

Sub matchData()


    Dim wb As Workbook, wsA As Worksheet, wsB As Worksheet, wsC As Worksheet
    Dim m As Variant, cDest As Range, c As Range
    
    Set wb = Workbooks("A")
    Set wsA = wb.Sheets("1")
    Set wsB = wb.Sheets("2")
    Set wsC = wb.Sheets("3")
    
    Set cDest = wsC.Range("A2") 'start pasting here
    
    For Each c In wsA.Range("D1:D" & wsA.Cells(Rows.Count, "D").End(xlUp).Row).Cells
        m = Application.Match(c.Value, wsB.Columns("A"), 0) 'Match is faster than Find
        If Not IsError(m) Then             'got a match?
            wsB.Rows(m).Copy cDest         'copy matched row
            Set cDest = cDest.Offset(1, 0) 'next paste row
        End If
    Next c
End Sub

Upvotes: 0

Views: 44

Answers (1)

Tim Williams
Tim Williams

Reputation: 166341

If you have duplicates in your lookup range then Match/Find get slower, so a dictionary-based approach can often be better:

Option Explicit

Sub MatchDataWithDups()

    Dim wb As Workbook, wsA As Worksheet, wsB As Worksheet, wsC As Worksheet
    Dim k, cDest As Range, c As Range, cK As Range
    Dim map As Object
    
    Set wb = Workbooks("A")
    Set wsA = wb.Sheets("1")
    Set wsB = wb.Sheets("2")
    Set wsC = wb.Sheets("3")
    
    'get a Dictionary mapping unique values to their respective cells on wsB
    Set map = RowMap(wsB.Range("A1:A" & wsB.Cells(Rows.Count, "A").End(xlUp).Row))
    Set cDest = wsC.Range("A2") 'start pasting here
    
    For Each c In wsA.Range("D1:D" & wsA.Cells(wsA.Rows.Count, "D").End(xlUp).Row).Cells
        k = c.Value
        If Len(k) > 0 Then
            If map.Exists(k) Then                  'matching value found?
                For Each cK In map(k).Cells        'loop the matched cell(s)
                    cK.EntireRow.Copy cDest        'copy the row
                    Set cDest = cDest.Offset(1, 0) 'next paste row
                Next cK
            End If
        End If
    Next c
End Sub

'Map all unique values in range `rngColumn` to
' a union'ed range of cells where they occur
Function RowMap(rngColumn As Range)
    Dim dict As Object, k, arr, i As Long
    Set dict = CreateObject("scripting.dictionary")
    arr = rngColumn.Value 'read range to array
    
    For i = 1 To UBound(arr, 1) 'loop over array
        k = arr(i, 1)
        If Not dict.Exists(k) Then
            dict.Add k, rngColumn.Cells(i) 'new key
        Else
            'existing key - add another cell
            Set dict(k) = Application.Union(dict(k), rngColumn.Cells(i))
        End If
    Next i
    Set RowMap = dict
End Function

Upvotes: 1

Related Questions