Consulting

Results 1 to 10 of 10

Thread: Solved: Delete Duplicate Values only... Not rows

  1. #1
    VBAX Regular
    Joined
    Jul 2010
    Posts
    15
    Location

    Solved: Delete Duplicate Values only... Not rows

    Hello,

    I am using Windows 7... Excel 2010.

    I am looking for a more efficient way to Delete Duplicate Values, in cells, in specified columns.
    I do not want to delete the rows in which the duplicates appear. Just keep the first instance of the value, and delete the others.

    I have been using this:

    [vba]
    Sub DeleteDups()
    Dim lastRow As Long, i As Long

    Application.ScreenUpdating = False

    With Sheets("Data")
    lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row

    For i = lastRow To 1 Step -1
    If Application.CountIf(.Range("C1:C" & lastRow), .Range("C" & i)) > 1 Then
    .Range("C" & i).ClearContents
    End If
    Next i
    End With

    Application.Screenupdating = True
    End Sub

    [/vba]

    And adding other columns to it as needed.

    But the data can be 15 or 20 K rows, and over multiple columns, it is slow. It does work though. Data keeps growing too.

    Attached is a sample.


    Many thanks In advance.

    C.R.
    Attached Files Attached Files

  2. #2
    Knowledge Base Approver VBAX Guru GTO's Avatar
    Joined
    Sep 2008
    Posts
    3,368
    Location
    Maybe something like:
    [VBA]Option Explicit
    Sub Example()
    Dim rngLastCell As Range
    Dim rngValues As Range
    Dim aryValues As Variant

    With Sheet1 '<--- Using CodeName,
    'OR,
    'Worksheet (Tab) name: ThisWorkbook.Worksheets ("Sheet1")

    '// Find cell in last row with data. //
    Set rngLastCell = RangeFound(.Range(.Cells(2, "A"), .Cells(.Rows.Count, "G")))

    '// Ensure data is there. //
    If rngLastCell Is Nothing Then Exit Sub
    If rngLastCell.Row < 3 Then Exit Sub

    '// Set a reference to the range,... //
    Set rngValues = .Range(.Cells(2, "A"), .Cells(rngLastCell.Row, "G"))
    End With

    '// and plunk all the values into an array, before... //
    aryValues = rngValues.Value

    '// passing the array ByRef, where the elements can get "emmptied" if duplicate.//
    StripDups aryValues, 3, 4, 5

    '// Plunk the array of values back into the range.
    rngValues.Value = aryValues
    End Sub

    Function StripDups(ValuesPassed, ParamArray WhichColumns() As Variant)
    Dim DIC As Object ' Dictionary
    Dim IndexParam As Long
    Dim IndexArrayRow As Long

    '// Set a reference to a created dictionary. //
    Set DIC = CreateObject("Scripting.Dictionary")

    '// Loop through each column selected to work against in the ParamArray //
    For IndexParam = LBound(WhichColumns) To UBound(WhichColumns)
    '// After the first loop, we'll want to dump whatever is in the dictionary. //
    If DIC.Count > 0 Then DIC.RemoveAll
    '// Run through the 'rows' in whatever 'column' of the array that we are in. //
    For IndexArrayRow = LBound(ValuesPassed, 1) To UBound(ValuesPassed, 1)
    '// If a key does not exist for the value, add an item/key. The item can //
    '// just stay empty, we are interested in the key only, for .Exists. //
    If Not DIC.Exists(ValuesPassed(IndexArrayRow, WhichColumns(IndexParam))) Then
    DIC.Item(ValuesPassed(IndexArrayRow, WhichColumns(IndexParam))) = Empty
    Else
    '// Else erase the value in the array. //
    ValuesPassed(IndexArrayRow, WhichColumns(IndexParam)) = vbNullString
    End If
    Next
    Next
    End Function

    Function RangeFound(SearchRange As Range, _
    Optional ByVal FindWhat As String = "*", _
    Optional StartingAfter As Range, _
    Optional LookAtTextOrFormula As XlFindLookIn = xlValues, _
    Optional LookAtWholeOrPart As XlLookAt = xlPart, _
    Optional SearchRowCol As XlSearchOrder = xlByRows, _
    Optional SearchUpDn As XlSearchDirection = xlPrevious, _
    Optional bMatchCase As Boolean = False) As Range

    If StartingAfter Is Nothing Then
    Set StartingAfter = SearchRange(1)
    End If

    Set RangeFound = SearchRange.Find(What:=FindWhat, _
    After:=StartingAfter, _
    LookIn:=LookAtTextOrFormula, _
    LookAt:=LookAtWholeOrPart, _
    SearchOrder:=SearchRowCol, _
    SearchDirection:=SearchUpDn, _
    MatchCase:=bMatchCase)
    End Function[/VBA]
    Hope that helps,

    Mark

  3. #3
    VBAX Tutor mohanvijay's Avatar
    Joined
    Aug 2010
    Location
    MADURAI
    Posts
    268
    Location
    Try this

    [vba]

    Sub Delete_Dup()
    Dim L_Rw As Long
    With ThisWorkbook.Sheets(1)
    L_Rw = .Cells(Rows.Count, 3).End(xlUp).Row

    .Range("i2").Value = "=IF(COUNTIF($C$1:$C$" & L_Rw & ",C2)>1," & _
    "IF(MATCH(C2,$C$1:$C$" & L_Rw & ",0)<>ROW(C2),1,""Cor""),""Cor"")"
    .Range("i2").Copy .Range("i2:i" & L_Rw)

    .Range("i2:i" & L_Rw).SpecialCells(xlCellTypeFormulas, 1).Offset(, -6).ClearContents
    .Range("i2:i" & L_Rw).ClearContents

    'try the same to rest two colums


    End With
    End Sub
    [/vba]

  4. #4
    VBAX Tutor mohanvijay's Avatar
    Joined
    Aug 2010
    Location
    MADURAI
    Posts
    268
    Location
    If the column "Line Item" is unique for the "Invoice #" then change the formula like below

    [vba]

    .Range("i2").Value = "=IF(F2=1,""Y"",1)"

    [/vba]

  5. #5
    Distinguished Lord of VBAX VBAX Grand Master Bob Phillips's Avatar
    Joined
    Apr 2005
    Posts
    25,453
    Location
    Do the values have to be deleted, could they just be hidden?

    If so, you could apply conditional formatting with a white font colour to the cells. Select C2:E20, and setup CF with a formula of

    =COUNTIF(C$1:C1,C2)>0

    and Format the font colour to white.

    This way,the values are still there if you want to use them in a formula, just show more cleanly.
    ____________________________________________
    Nihil simul inventum est et perfectum

    Abusus non tollit usum

    Last night I dreamed of a small consolation enjoyed only by the blind: Nobody knows the trouble I've not seen!
    James Thurber

  6. #6
    VBAX Regular
    Joined
    Jul 2010
    Posts
    15
    Location
    All,

    I am just waking up, and, I am exited to try these solutions when I get into the office today. xld... Conditional formatting never even crossed my mind. Mark and monhanvijay... thank you very much for your solutions. I will test them in a couple hours. I've been lurking here for a while, but this was my first post. This place is great!

    Best Regards,

    Kevin

  7. #7
    Knowledge Base Approver VBAX Wizard
    Joined
    Apr 2012
    Posts
    5,645
    I think this suffices:

    [vba]Sub snb()
    [sheet1!C1:C40] = [if(countif(offset(sheet1!C1,,,row(C1:C40)),sheet!C1:C40)=1,sheet1!C1:C40,"" )]
    End Sub[/vba]

  8. #8
    Sub DeleteDups(ByVal ColToManage as Integer)
    Dim lastRow As Long, i As Long

    Application.ScreenUpdating = False
    With
    Sheets("Data")
    lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
    End With

    Sheets("Data").Activate
    For i = lastRow to 2 Step -1
    If Cells(i,ColToManage).Value = Cells(i-1,ColToManage).Value Then
    Cells(i,ColToManage).Value=""
    End If
    Next i

    Application.Screenupdating = True

    End Sub


    For each of other columns Change ColToManage

  9. #9
    [VBA][/VBA]
    .............. For i = lastRow To 2 Step -1 If Cells(i,"C")= Cells(i-,"C") Then Cells(i,"C").Value="" End If Next i
    ..............

  10. #10
    VBAX Regular
    Joined
    Jul 2010
    Posts
    15
    Location
    Thank you everyone.
    I have more solutions than I ever needed.
    So much to learn.

    Kevin

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •