sc1324
sc1324

Reputation: 600

How to get the list of duplicated values in a range

I tried recording the macros but it's using copying and pasting, but I prefer the codes to be dynamic as the range of my data changes weekly.

I have 2 columns, A & D. Column A is a pivot table, so I think, maybe that's why VBA codes for moving down rows don't work. (error for trying to move pivot table). I want Column D to be a list of unique duplicates that are from column A and condense it so no gaps.

So far I can extract the unique duplicates and condense them but the results are pasted it from D1 instead of D8. So I need help to bring down the values 8 rows. Now I don't want to copy and paste the pivot table as values or trying to get rid of it since I need the pivot table there as I can just refresh it every week for new list.

Any suggestion or advice is appreciated.

    Sub dp()

    AR = Cells(Rows.Count, "A").End(xlUp).Row

    For Each p1 In Range(Cells(8, 1), Cells(AR, 1))
        For Each p2 In Range(Cells(8, 1), Cells(AR, 1))
            If p1 = p2 And Not p1.Row = p2.Row Then
                Cells(p1.Row, 4) = Cells(p1.Row, 1)
                Cells(p2.Row, 4) = Cells(p2.Row, 1)
            End If
        Next p2
    Next p1
    Columns(4).RemoveDuplicates Columns:=Array(1)
        Dim lastrow As Long
        Dim i As Long
        lastrow = Range("D:D").End(xlDown).Row

        For i = lastrow To 1 Step -1

        If IsEmpty(Cells(i, "D").Value2) Then

            Cells(i, "D").Delete shift:=xlShiftUp
        End If
    Next i
End Sub

enter image description here

Upvotes: 4

Views: 1356

Answers (4)

user6432984
user6432984

Reputation:

Here are three different techniques:

  1. ArraysList
  2. ADODB.Recordset
  3. Array and CountIf

ArraysList

Sub ListDuplicates()
    Dim v, listValues, listDups
    Set listValues = CreateObject("System.Collections.ArrayList")
    Set listDups = CreateObject("System.Collections.ArrayList")

    For Each v In Range("A8", Cells(Rows.Count, "A").End(xlUp)).Value
        If listValues.Contains(v) And Not listDups.Contains(v) Then listDups.Add v
        listValues.Add v
    Next

    Range("D8").Resize(listDups.Count).Value = Application.Transpose(listDups.ToArray)
End Sub

ADODB.Recordset

Sub QueryDuplicates()
    Dim rs As Object, s As String
    Set rs = CreateObject("ADODB.Recordset")
    s = ActiveSheet.Name & "$" & Range("A7", Cells(Rows.Count, "A").End(xlUp)).Address(False, False)
    rs.Open "SELECT [Pivot Table] FROM [" & s & "] GROUP BY [Pivot Table] HAVING COUNT([Pivot Table]) > 1", _
            "Provider=MSDASQL;DSN=Excel Files;DBQ=" & ThisWorkbook.FullName

    If Not rs.EOF Then Range("D8").CopyFromRecordset rs
    rs.Close
    Set rs = Nothing
End Sub

Array and CountIf (similar to SJR answer but using an array to gather the data)

Sub ListDuplicatesArray()
    Dim v, vDups
    Dim x As Long, y As Long
    ReDim vDups(x)
    With Range("A8", Cells(Rows.Count, "A").End(xlUp))

        For Each v In .Value
            If WorksheetFunction.CountIf(.Cells, v) > 1 Then
                For y = 0 To UBound(vDups)
                    If vDups(y) = v Then Exit For
                Next
                If y = UBound(vDups) + 1 Then
                    ReDim Preserve vDups(x)
                    vDups(x) = v
                    x = x + 1
                End If

            End If
        Next
    End With

    Range("D8").Resize(UBound(vDups) + 1).Value = Application.Transpose(vDups)
End Sub

Upvotes: 2

user3598756
user3598756

Reputation: 29421

here's another approach:

Option Explicit

Sub main()
    Dim vals As Variant, val As Variant
    Dim strng As String

    With Range(Cells(8, 1), Cells(Rows.count, 1).End(xlUp))
        vals = Application.Transpose(.Value)
        strng = "|" & Join(vals, "|") & "|"
        With .Offset(, 3)
            .Value = Application.Transpose(vals)
            .RemoveDuplicates Columns:=1, Header:=xlNo
            For Each val In .SpecialCells(xlCellTypeConstants)
                strng = Replace(strng, val, "", , 1)
            Next val
            vals = Split(WorksheetFunction.Trim(Replace(strng, "|", " ")), " ")
            With .Resize(UBound(vals) + 1)
                .Value = Application.Transpose(vals)
                .RemoveDuplicates Columns:=1, Header:=xlNo
            End With
        End With
    End With
End Sub

Upvotes: 2

Vasily
Vasily

Reputation: 5782

another one approach here

Sub dp2()
    Dim n&, c As Range, rng As Range, Dic As Object
    Set Dic = CreateObject("Scripting.Dictionary")
    Dic.comparemode = vbTextCompare
    Set rng = Range("A8:A" & Cells(Rows.Count, "A").End(xlUp).Row)
    n = 8
    For Each c In rng
        If Dic.exists(c.Value2) And Dic(c.Value2) = 0 Then
            Dic(c.Value2) = 1
            Cells(n, "D").Value2 = c.Value2
            n = n + 1
        ElseIf Not Dic.exists(c.Value2) Then
            Dic.Add c.Value2, 0
        End If
    Next c
End Sub

but if you prefer your own variant, then you need to:
1) replace this line of code: Columns(4).RemoveDuplicates Columns:=Array(1)
by this one: Range("D8:D" & Cells(Rows.Count, "D").End(xlUp).Row).RemoveDuplicates Columns:=1
2) another problem is in this line of code: lastrow = Range("D:D").End(xlDown).Row
it will return the row #8 instead of last row that you've expected, so you need to replace it by this one: lastrow = Cells(Rows.Count, "D").End(xlUp).Row

3) also, replace to 1 step -1 by to 8 step -1

so, finally your code can looks like this:

Sub dp()
    Dim AR As Long, p1 As Range, p2 As Range, lastrow&, i&
    AR = Cells(Rows.Count, "A").End(xlUp).Row
    For Each p1 In Range(Cells(8, 1), Cells(AR, 1))
        For Each p2 In Range(Cells(8, 1), Cells(AR, 1))
            If p1 = p2 And Not p1.Row = p2.Row Then
                Cells(p1.Row, 4) = Cells(p1.Row, 1)
                Cells(p2.Row, 4) = Cells(p2.Row, 1)
            End If
    Next p2, p1
    Range("D8:D" & Cells(Rows.Count, "D").End(xlUp).Row).RemoveDuplicates Columns:=1
    lastrow = Cells(Rows.Count, "D").End(xlUp).Row
    For i = lastrow To 8 Step -1
        If IsEmpty(Cells(i, "D").Value2) Then
            Cells(i, "D").Delete shift:=xlShiftUp
        End If
    Next i
End Sub

Upvotes: 1

SJR
SJR

Reputation: 23081

Here is a different approach

Sub dp()

Dim AR As Long, p1 As Range, n As Long

AR = Cells(Rows.Count, "A").End(xlUp).Row
n = 8
With Range(Cells(8, 1), Cells(AR, 1))
    For Each p1 In .Cells
        If WorksheetFunction.CountIf(.Cells, p1) > 1 Then
            If WorksheetFunction.CountIf(Columns(4), p1) = 0 Then
                Cells(n, "D") = p1
                n = n + 1
            End If
        End If
    Next p1
End With

End Sub

Upvotes: 4

Related Questions