Clear adjacent duplicates only - excel

This sub clears duplicate rows between two columns.
If it finds a new pair in columns F & G, it will clear that pair throughout F & G.
I'm trying to clear values that are directly below the original values.
I'm trying to reset after a duplicate been cleared, so that it doesn't clear values that aren't directly below the original values.
Sub clearDups1()
Dim lngMyRow As Long
Dim lngMyCol As Long
Dim lngLastRow As Long
Dim objMyUniqueData As Object
Application.ScreenUpdating = False
lngLastRow = Range("F:G").Find("*", SearchOrder:=xlByRows, SearchDirection:=xlPrevious).row
Set objMyUniqueData = CreateObject("Scripting.Dictionary")
For lngMyRow = 1 To lngLastRow 'Assumes the data starts at row 1. Change to suit if necessary.
If objMyUniqueData.Exists(CStr(Cells(lngMyRow, 6) & Cells(lngMyRow, 7))) = False Then
objMyUniqueData.Add CStr(Cells(lngMyRow, 6) & Cells(lngMyRow, 7)), Cells(lngMyRow, 6) & Cells(lngMyRow, 7)
Else
Range(Cells(lngMyRow, 6), Cells(lngMyRow, 7)).ClearContents
End If
Next lngMyRow
Set objMyUniqueData = Nothing
Application.ScreenUpdating = True
End Sub
Any input appreciated.

You don't need a dictionary for this:
Sub clearDups1()
Dim lngMyRow As Long, lngLastRow As Long, ws As Worksheet
Dim k As String, kPrev As String
Set ws = ActiveSheet
lngLastRow = ws.Range("F:G").Find("*", SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious).row
Application.ScreenUpdating = False
kPrev = Chr(0) 'won't occur in your data
For lngMyRow = 1 To lngLastRow 'Assumes the data starts at row 1. Change to suit if necessary.
k = CStr(ws.Cells(lngMyRow, 6).Value) & "<>" & CStr(ws.Cells(lngMyRow, 7).Value)
If kCurr = k Then 'same as previous row?
ws.Cells(lngMyRow, 6).Resize(1, 2).ClearContents
End If
kPrev = k 'set as key for previous row
Next lngMyRow
Application.ScreenUpdating = True
End Sub

You can also try this code. It does what you have asked.
Leave the first occurring of the same dups
Start from the bottom to delete them and leave the final which in our case will be original
Using the above ways you can achieve what you have asked for.
Sub clearDups()
Dim lR As Long, r As Long
Dim x As 99999
Dim f(x), g(x) As String
Dim lRow As Long, lCol As Long, i As Long
lRow = Range("F" & Rows.Count).End(xlUp).Row
For lR = 2 To lRow
f(lR - 1) = Cells(lR, "F").Value
g(lR - 1) = Cells(lR, "G").Value
Next
For Each s In f
i = i + 1
If Application.CountIf(Range("F1:G" & lRow), s) = 2 Then
Cells(i, "F").Value = ""
Cells(i, "G").Value = ""
End If
Next
End Sub

Related

Move duplicates rows above

I have sheet1 and sheet10 to run a macro to find duplicates comparing column A and B.
Highlight color duplicates, in column A, move duplicates to first row A1.
Any help will appreciate, thank you in advance.
Macro need to run in sheet 1 and sheet 10 maybe less sheets.
Sub sbFindDuplicatesInColumn()
Dim lastRow As Long
Dim matchFoundIndex As Long
Dim iCntr As Long
lastRow = Range("A1:C").End(xlUp).Row
For iCntr = 1 To lastRow
If Cells(iCntr, 1) <> "" Then
matchFoundIndex = WorksheetFunction.Match(Cells(iCntr, 1), Range("A1:A" & lastRow), 0)
If iCntr <> matchFoundIndex Then
Cells(iCntr, 2) = "Duplicate"
End If
End If
Next
End Sub
Build a range of the duplicate cells using Union, copy and insert them in the first row and then delete them.
Sub sbFindDuplicatesInColumn2()
Const DUP_COLOR = &H9696FF ' pink
Dim ws, rngDup As Range, c As Range
Dim arC, v, sht, lastRow As Long, n As Long
For Each sht In Array("Sheet1", "Sheet10")
Set ws = Sheets(sht)
n = 0
With ws
.Cells.ClearFormats
lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
arC = .Range("C1:C" & lastRow) ' array
lastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For Each c In .Range("A1:A" & lastRow)
v = Application.Match(c.Value2, arC, 0)
If Not IsError(v) Then
.Cells(v, "C").Interior.Color = DUP_COLOR
If n = 0 Then
Set rngDup = c
Else
Set rngDup = Application.Union(rngDup, c)
End If
n = n + 1
End If
Next
' move cells and sort
If n > 0 Then
' copy to top
.Range("A1").Resize(n).Insert shift:=xlDown
rngDup.Copy .Range("A1")
.Range("A1:A" & n).Interior.Color = DUP_COLOR
' delete
rngDup.Delete shift:=xlUp
' sort
With .Sort
.SetRange ws.Range("A1:A" & n)
.Header = xlNo
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
End If
End With
MsgBox n & " Duplicates found in " & ws.Name, vbInformation
Next
End Sub
You should add comparing the values of ranges
Sub sbFindDuplicatesInColumn()
Dim lastRow As Long
Dim matchFoundIndex As Long
Dim iCntr As Long
lastRow = Range("A1:C").End(xlUp).Row
For iCntr = 1 To lastRow
If Cells(iCntr, 1) <> "" Then
matchFoundIndex = WorksheetFunction.Match(Cells(iCntr, 1), Range("A1:A" & lastRow), 0)
If iCntr <> matchFoundIndex AND Cells(iCntr,1).Value <> Range("A1:A" & lastRow).Value
Then
Cells(iCntr, 2) = "Duplicate"
End If
End If
Next
End Sub

Insert Row when 2 conditions are met

I have created below code which works like IF Col"B" any cell <> "" And Col"L" any cell = "Leop" then add row below to the active cell.
I mean I'm trying to achieve is to insert single row after certain row which contain in column B any value, and if column L in same row contains value = "Leop". Then add the row after that certain row.
But an error is appear. Compile Error: Invalid use of property on xlDown
Your help will be appreciated to fix it.
From this:
to this:
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long
Dim rng As Range
Dim rng2 As Range
Dim i As Long
Dim p As Long
Dim dat As Variant
Dim datt As Variant
Dim IRow As Long
Set ws = Thisworkbooks.Sheets("Sheet2")
With ws
LRow = .Range("A" & .Rows.Count).End(xlUp).Row
Set rng = .Range("B2:B" & LRow)
Set rng2 = .Range("L2:L" & LRow)
dat = rng
datt = rng2
IRow = Selection.Row
For i = LBound(dat, 1) To UBound(dat, 1)
For p = LBound(datt, 1) To UBound(datt, 1)
If dat(i, 1) <> "" And datt(p, 1) = "Leop" Then
Rows(IRow + 1).Select
Selection.Insert Shift: xlDown
End If
End Sub
It will be like in formula:
IF(AND(B2<>"",L2="Leop"),"InsertRowBelow to Row 2 If condition is met","")
and will drag it down to the lastRow.
Thisworkbooks.Sheets("Sheet2") should be Thisworkbook.Sheets("Sheet2") and missing = in Selection.Insert Shift:= xlDown
Inserting or deleting rows will change the last row number so start at the bottom and work upwards.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet, LRow As Long, r As Long
Dim n As Long
Set ws = ThisWorkbook.Sheets("Sheet2")
With ws
LRow = .Range("B" & .Rows.Count).End(xlUp).Row
For r = LRow To 2 Step -1
If .Cells(r, "B") <> "" And .Cells(r, "L") = "Leop" Then
.Rows(r + 1).Insert shift:=xlDown
n = n + 1
End If
Next
End With
MsgBox n & " rows inserted", vbInformation
End Sub
Try this with autofilter, you dont have to loop through each row. So it will work faster for larger data.
Option Explicit
Sub firstcondition()
Dim ws As Worksheet
Dim LRow As Long, cl As Range
Set ws = ThisWorkbook.Sheets("Sheet2")
LRow = ws.Range("A" & ws.Rows.Count).End(xlUp).Row
ws.Range("L1:L" & LRow).AutoFilter 1, "Leop"
For Each cl In ws.Range("_FilterDatabase").SpecialCells(12).Cells
If ws.Range("B" & cl.Row) <> "" Then
cl.Offset(1).EntireRow.Insert Shift:=xlDown
End If
Next
ws.AutoFilterMode = False
End Sub

Count unique values and return results in another column

I have values in column B (green, blue, white....) and I want to count them and the result must appear in column A in the following format (green01, green02, green03...., blue01, blue02, blue03, blue04...., white01, white 02...).
The result must look like in this photo
I have searched the net for a macro, but I didn't find one to fit my needs.
THX
No VBA needed, in A1:
=B1&TEXT(COUNTIF(B$1:B1,B1),"00")
Try the next code, please:
Sub testCountSortColors()
Dim sh As Worksheet, lastRow As Long, i As Long, c As Long
Set sh = ActiveSheet
lastRow = sh.Range("B" & Rows.count).End(xlUp).Row
sh.Range("B1:B" & lastRow).Sort key1:=sh.Range("B1"), order1:=xlAscending, Header:=xlYes
For i = 2 To lastRow
If sh.Range("B" & i).value <> sh.Range("B" & i - 1).value Then
c = 1
Else
c = c + 1
End If
sh.Range("A" & i).value = sh.Range("B" & i).value & Format(c, "00")
sh.Range("A" & i).Font.Color = sh.Range("B" & i).Font.Color
Next
End Sub
I thought you maybe have column headers...
A Unique Count
Adjust the values in the constants section.
Option Explicit
Sub countUnique()
Const SourceColumn As Variant = 2 ' e.g. 2 or "B"
Const TargetColumn As Variant = 1 ' e.g. 1 or "A"
Const FirstRow As Long = 1
Dim rng As Range
Dim dict As Object
Dim Key As Variant
Dim Source As Variant, Target As Variant
Dim i As Long, UB As Long
Dim CurrString As String
Set rng = Columns(SourceColumn).Find(What:="*", _
LookIn:=xlFormulas, SearchDirection:=xlPrevious)
If rng Is Nothing Then GoTo exitProcedure
If rng.Row < FirstRow Then GoTo exitProcedure
Source = Range(Cells(FirstRow, SourceColumn), rng)
Set rng = Nothing
UB = UBound(Source)
Set dict = CreateObject("Scripting.Dictionary")
For i = 1 To UB
If Source(i, 1) <> "" Then
dict(Source(i, 1)) = dict(Source(i, 1)) + 1
End If
Next i
ReDim Target(1 To UB, 1 To 1)
For i = UB To 1 Step -1
CurrString = Source(i, 1)
If CurrString <> "" Then
Target(i, 1) = CurrString & Format(dict(CurrString), "00")
dict(CurrString) = dict(CurrString) - 1
End If
Next i
With Cells(FirstRow, TargetColumn)
.Resize(Rows.Count - FirstRow + 1).ClearContents
.Resize(UB) = Target
End With
MsgBox "Operation finished successfully."
exitProcedure:
End Sub

Loop, find cells with value then search column for the same cell and change its value

Detailed Problem
I'm attempting to write a VBA code that would loop through Column D,
if it finds Cells(i,"D") = "Good" then the code would search the entire column D for that value in cells (i,"D") and change all it's value to "Good"
Here is an Image on before the code.
Here is an Image after the code.
My Attempt:
Dim i As Integer
For i = 1 To Rows.Count
If Cells(i, "m") = "Good" Then
x = Cells(i, "m")
Next i
I think you would have to store the value ( ID Number ) and then search for it which I assigned "X". Once "X" is found change the status to "Good"
Use an AutoFilter
Option Explicit
Sub makeGood()
Dim i As Long, tmp As Variant
Dim dict As Object, k As Variant
'late bind a dictionary
Set dict = CreateObject("scripting.dictionary")
dict.CompareMode = vbTextCompare
With Worksheets("sheet11")
'remove any existing autofilters
If .AutoFilterMode Then .AutoFilterMode = False
'collect values from column D
tmp = .Range(.Cells(2, "D"), .Cells(.Rows.Count, "D").End(xlUp)).Value
'build dictionary of unique ID NUMs
For i = LBound(tmp, 1) To UBound(tmp, 1)
dict.Item(tmp(i, 1)) = vbNullString
Next i
'work with D:G range
With .Range(.Cells(1, "D"), .Cells(.Rows.Count, "G").End(xlUp))
'loop through unique ID NUMs
For Each k In dict.Keys
'autofilter on key
.AutoFilter field:=1, Criteria1:=k, visibledropdown:=False
'autofilter on Good
.AutoFilter field:=4, Criteria1:="good", visibledropdown:=False
'check for visible cells
If Application.Subtotal(103, .Offset(1, 0).Cells) > 0 Then
'remove the Good autofilter
.AutoFilter field:=4
'step down off the header and put Good in the filtered cells
With .Resize(.Rows.Count - 1, 1).Offset(1, 3)
.SpecialCells(xlCellTypeVisible) = "Good"
End With
End If
'clear autofilter
.AutoFilter field:=1
.AutoFilter field:=4
Next k
End With
End With
End Sub
May be a bit convoluted, but here is an idea.
Sub f(strSearchFor as string)
Dim r As Excel.Range
Dim d As New Scripting.Dictionary
Set r = Range("a1:b10")
For Each c In r.Columns(2).Cells
If StrComp(c.Value, strSearchFor, vbTextCompare) = 0 Then
If Not d.Exists(c.Value) Then
d.Add c.Offset(0, -1).Value, c.Value
End If
End If
Next c
For Each c In r.Columns(1).Cells
If d.Exists(c.Value) Then
c.Offset(0, 1).Value = d(c.Value)
End If
Next c
Set r = Nothing
Set d = Nothing
End Sub
You can add a helper column and do it with a formula only:
Add the following formula eg. in H2 (of your example) and pull it down:
=IF(COUNTIFS(D:D,D2,G:G,"Good")>0,"Good",G2)
You could try:
Option Explicit
Sub trst()
Dim i As Long, y As Long, LastRow As Long
Dim ID As String, Status As String
With ThisWorkbook.Worksheets("Sheet1") '<- Change Workbook / Sheet names
LastRow = .Cells(.Rows.Count, "A").End(xlUp).Row
For i = 2 To LastRow
ID = .Range("D" & i).Value
Status = .Range("G" & i).Value
For y = 2 To LastRow
If ID = .Range("D" & y).Value Then
.Range("G" & y).Value = Status
End If
Next y
Next i
End With
End Sub
Test with arrais. With arrais it is much faster
Option Explicit
Sub Subst()
With ThisWorkbook.Sheets("Sheet1")
Dim ArrayColumnD As Variant
ArrayColumnD = .Range("D1:D" & .Cells(.Rows.Count, 4).End(xlUp).Row)
Dim ArrayColumnG As Variant
ArrayColumnG = .Range("G1:G" & .Cells(.Rows.Count, 7).End(xlUp).Row)
Dim ID As String
Dim RowActual As Long
Dim RowTest As Long
For RowActual = 2 To UBound(ArrayColumnD)
If ArrayColumnG(RowActual, 1) = "Good" Then
ID = ArrayColumnD(RowActual, 1)
For RowTest = 2 To UBound(ArrayColumnD)
If ArrayColumnD(RowTest, 1) = ID Then
ArrayColumnG(RowTest, 1) = "Good"
End If
Next RowTest
End If
Next RowActual
.Range("G1:G" & .Cells(.Rows.Count, 7).End(xlUp).Row) = ArrayColumnG
End With
End Sub

VBA insert rows_dynamic

Below is the piece of code in VBA which basically insert no of rows based on a count present in a specific cell, Now I want to change the code so that no of rows that will be inserted is to be one less then the count present in a specific cell.
for eg- if in a specific column and specific cell count=N then macro will runn and add N no of rows.Now I want rows is to be added is one less i.e N-1
Sub InsertRowsIf()
Dim lr As Long, R As Range, i As Long
lr = Range("R" & Rows.Count).End(xlUp).Row
Set R = Range("R3", "R" & lr)
Application.ScreenUpdating = False
For i = R.Rows.Count To 1 Step -1
If IsNumeric(R.Cells(i, 1).Value) And Not IsEmpty(R.Cells(i, 1)) Then
R.Cells(i, 1).Offset(1, 0).Resize(R.Cells(i, 1).Value).EntireRow.Insert
End If
Next i
End Sub
I think by trying to insert the use of R as a Range is causing issues. It is not needed.
Sub InsertRowsIf()
Dim ws As Worksheet
Set ws = Worksheets("Sheet1") ' Change to your sheet
Dim lr As Long
lr = ws.Range("R" & Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
Dim i As Long
For i = lr To 3 Step -1
If IsNumeric(ws.Cells(i, 18).Value) And ws.Cells(i, 18) <> "" Then
ws.Cells(i, 1).Offset(1,0).Resize(ws.Cells(i, 18).Value - 1).EntireRow.Insert
End If
Next i
Application.ScreenUpdating = True
End Sub
You forgot to turn ScreenUpdating back on. Updated code to skip last row and applied standard indentation.
Option Explicit
Sub InsertRowsIf()
Dim lr As Long, R As Range, i As Long
lr = Range("R" & Rows.Count).End(xlUp).Row
Set R = Range("R3:R" & lr - 1)
Application.ScreenUpdating = False
For i = R.Rows.Count To 1 Step -1
If IsNumeric(R.Cells(i, 1).Value) And Not IsEmpty(R.Cells(i, 1)) Then
R.Cells(i, 1).Offset(1, 0).Resize(R.Cells(i, 1).Value).EntireRow.Insert
End If
Next i
Application.ScreenUpdating = True
End Sub

Resources