Search code examples
excelvbaduplicatescopycopy-paste

How to find duplicate values in a column and copy paste the rows found duplicated?


There are duplicated values in the first column (ISIN numbers of financial products), but different characteristics in the other columns (product name, modified duration, etc.) where should be the same characteristics.

I want to find ISIN numbers that already exist in my first column (at least two times), then take specific elements from the other columns (of the same row that was found the duplicated value) such as issuer name, modified duration etc. and paste them to the other's ISIN elements to report the same elements (data in other columns) in case where ISIN numbers are the same.

I also want to compare the modified duration of these duplicated products and take the bigger one (for conservative reasons, because these data are used in further calculations).

Sub dup_cp()

Dim i As Integer
Dim j As Integer
Dim k As Integer

Sheets("Investment Assets").Activate
j = Application.CountA(Range("A:A")) 
'counts the number of filled in rows

For i = 5 To j
'it starts from line 5 on purpose, the ISIN numbers start from that line
    For k = i + 1 To j
        If Sheets("Investment Assets").Range(Cells(k, 55), Cells(k, 55)).Value = "Duplicate Value" Then GoTo skip_dup 
        'it skips the line that has already been detected as duplicated
           
        If Sheets("Investment Assets").Range(Cells(k, 1), Cells(k, 1)).Value = Sheets("Investment Assets").Range(Cells(i, 1), Cells(i, 1)).Value Then 
        'it finds the duplicate value (ISIN number) in the first column
            If Sheets("Investment Assets").Range(Cells(k, 29), Cells(k, 29)).Value >= Sheets("Investment Assets").Range(Cells(i, 29), Cells(i, 29)).Value Then 
            'it compares the 29th column values (the modified duration of the components) and keeps the bigger value for prudency reasons
                Sheets("Investment Assets").Range(Cells(k, 15), Cells(k, 32)).Copy
                Sheets("Investment Assets").Range(Cells(i, 15), Cells(i, 32)).PasteSpecial Paste:=xlPasteValues
            Else
                Sheets("Investment Assets").Range(Cells(i, 15), Cells(i, 32)).Copy
                Sheets("Investment Assets").Range(Cells(k, 15), Cells(k, 32)).PasteSpecial Paste:=xlPasteValues
            End If
            Sheets("Investment Assets").Range(Cells(k, 55), Cells(k, 55)).Value = "Duplicate Value"
            'it shows in the 55th column if the ISIN number is duplicated or not
            Sheets("Investment Assets").Range(Cells(i, 55), Cells(i, 55)).Value = "Duplicate Value"
        Else
            Sheets("Investment Assets").Range(Cells(k, 55), Cells(k, 55)).Value = "-"
        End If
skip_dup:
    Next
Next

End Sub

This code works, but is messy. Can it be made simpler and faster?


Solution

  • Changed a few things. As said before, Copy and Activate are the biggest drags on performance. I have introduced a With statement instead of Activate and have changed Copy, Paste to a faster ....Value = ....Value

    Sub dup_cp()
    
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer
    
    With Sheets("Investment Assets")
        j = Application.CountA(.Range("A:A"))
        'counts the number of filled in rows
    
        For i = 5 To j
        'it starts from line 5 on purpose, the ISIN numbers start from that line
            For k = i + 1 To j
                If .Cells(k, 55).Value = "Duplicate Value" Then GoTo skip_dup
                'it skips the line that has already been detected as duplicated
    
                If .Cells(k, 1).Value = .Cells(i, 1).Value Then
                'it finds the duplicate value (ISIN number) in the first column
                    If .Cells(k, 29).Value >= .Cells(i, 29).Value Then
                    'it compares the 29th column values (the modified duration of the components) and keeps the bigger value for prudency reasons
                        .Range(.Cells(i, 15), .Cells(i, 32)).Value = .Range(.Cells(k, 15), .Cells(k, 32)).Value
                    Else
                        .Range(.Cells(k, 15), .Cells(k, 32)).Value = .Range(.Cells(i, 15), .Cells(i, 32)).Value
                    End If
                    .Cells(k, 55).Value = "Duplicate Value"
                    'it shows in the 55th column if the ISIN number is duplicated or not
                    .Cells(i, 55).Value = "Duplicate Value"
                Else
                    .Cells(k, 55).Value = "-"
                End If
    skip_dup:
            Next
        Next
    End With
    
    End Sub
    

    Old Nick's proposal is also very great for performance, but I would implement it with care, something like this:

    Sub xxx
    
        On Error GoTo ErrorHandler
    
        Application.ScreenUpdating = False
        Application.Calculation = xlCalculationManual
        Application.EnableEvents = False
    
        'Your code
    
    ErrorHandler:
        If Err.Number <> 0 Then MsgBox Err.Number & " " & Err.Description
        Application.ScreenUpdating = True
        Application.Calculation = xlCalculationAutomatic
        Application.EnableEvents = True
    
    End Sub
    

    Because if you disable those things at the beginning, and then suddenly something goes wrong in the code, you might not get those things re-enabled.