Delete Duplicate Cell Contents in Column - vba

I am trying to delete the contents of duplicate cells in a single column. I want to keep the first occurrence of the entry, but remove all duplicates below it.
I could only find code that deletes the entire row and not clear the contents.
Sub Duplicate()
With Application
' Turn off screen updating to increase performance
.ScreenUpdating = False
Dim LastColumn As Integer
LastColumn = Cells.Find(What:="*", After:=Range("U1"), SearchOrder:=xlByColumns, SearchDirection:=xlPrevious).Column + 1
With Range("U1:U" & Cells(Rows.Count, 1).End(xlUp).Row)
' Use AdvanceFilter to filter unique values
.AdvancedFilter Action:=xlFilterInPlace, Unique:=True
.SpecialCells(xlCellTypeVisible).Offset(0, LastColumn - 1).Value = 1
On Error Resume Next
ActiveSheet.ShowAllData
'Delete the blank rows
Columns(LastColumn).SpecialCells(xlCellTypeBlanks).Cells.Clear
Err.Clear
End With
Columns(LastColumn).Clear
.ScreenUpdating = True
End With
End Sub

Here is one way. We start at the bottom of a column and work upwards:
Sub RmDups()
Dim A As Range, N As Long, i As Long, wf As WorksheetFunction
Dim rUP As Range
Set A = Range("A:A")
Set wf = Application.WorksheetFunction
N = Cells(Rows.Count, "A").End(xlUp).Row
For i = N To 2 Step -1
Set rUP = Range(Cells(i - 1, 1), Cells(1, 1))
If wf.CountIf(rUP, Cells(i, 1).Value) > 0 Then Cells(i, 1).Clear
Next i
End Sub
We check above to see if there are any duplicates above us and clear the cell if yes. Before:
and after:
EDIT#1:
For column U:
Sub RmDupsU()
Dim U As Range, N As Long, i As Long, wf As WorksheetFunction
Dim rUP As Range
Set U = Range("U:U")
Set wf = Application.WorksheetFunction
N = Cells(Rows.Count, "U").End(xlUp).Row
For i = N To 2 Step -1
Set rUP = Range(Cells(i - 1, "U"), Cells(1, "U"))
If wf.CountIf(rUP, Cells(i, "U").Value) > 0 Then Cells(i, "U").Clear
Next i
End Sub

my 0.02 cents
Sub main()
Dim i As Long
With Range("A1", Cells(Rows.Count, 1).End(xlUp))
For i = 1 To .Rows.Count - 1
.Range(.Cells(i + 1, 1), .Cells(.Rows.Count)).Replace what:=.Cells(i, 1).Value, replacement:="", lookat:=xlWhole
Next i
End With
End Sub

Here is a routine that will work. It can be sped up considerably if necessary:
EDIT: I changed column number to column letter, where you would need to make changes if you want a column other than "A"
Option Explicit
Sub ClearDups()
Dim R As Range
Dim I As Long
Dim COL As Collection
Set R = Range(Cells(1, "A"), Cells(Rows.Count, "A").End(xlUp))
Set COL = New Collection
On Error Resume Next
For I = 1 To R.Rows.Count
COL.Add Item:=R(I, 1), Key:=CStr(R(I, 1))
Select Case Err.Number
Case 457 'Duplicate test (Collection object rejects duplicate keys)
Err.Clear
R(I, 1).ClearContents
Case Is <> 0 'unexpected error
MsgBox Err.Number & vbLf & Err.Description
End Select
Next I
On Error Goto 0
End Sub

'This code crisply does the job of clearing the duplicate values in a given column
Sub jkjFindAndClearDuplicatesInGivenColumn()
dupcol = Val(InputBox("Type column number"))
lastrow = Cells(Rows.Count, dupcol).End(xlUp).Row
For n = 1 To lastrow
nval = Cells(n, dupcol)
For m = n + 1 To lastrow
mval = Cells(m, dupcol)
If mval = nval Then
Cells(m, dupcol) = ""
End If
Next m
Next n
End Sub

Related

VBA Combine columns stack in the loop

I have the issue with stacking in the loop
The macro should combine all columns (changeable number of rows) into one column.
Sub CombineColumns()
Dim xRng As Range
Dim i As Integer
Dim xLastRow As Integer
On Error Resume Next
Set xRng = Application.Range("A1", Range("A1").End(xlDown).End(xlToRight))
xLastRow = xRng.Columns(1).Rows.Count + 1
For i = 2 To xRng.Columns.Count
Range(xRng.Cells(1, i), xRng.Cells(xRng.Columns(i).Rows.Count, i)).Cut
ActiveSheet.Paste Destination:=xRng.Cells(xLastRow, 1)
xLastRow = xLastRow + xRng.Columns(i).Rows.Count
Next
End Sub
Using Array is simple and fast.
Sub test()
Dim Ws As Worksheet, toWS As Worksheet
Dim vDB, vR()
Dim i As Long, j As Integer, n As Long
Set Ws = ActiveSheet
vDB = Ws.UsedRange
r = UBound(vDB, 1)
c = UBound(vDB, 2)
For i = 1 To r
For j = 1 To c
n = n + 1
ReDim Preserve vR(1 To n)
vR(n) = vDB(i, j)
Next j
Next i
Set toWS = Sheets.Add ' set toWs = Sheets(2) ~~> set your sheet
With toWS
.Cells.Clear
.Range("a1").Resize(n) = WorksheetFunction.Transpose(vR)
End With
End Sub
If I got you right you want to do sth. like that
Option Explicit
Sub CombineColumns()
Dim xRng As Range
Dim i As Long
Dim xLastRow As Long
'On Error Resume Next
Set xRng = Application.Range("A1", Range("A1").End(xlToRight))
xLastRow = lastRow(1) + 1
For i = 2 To xRng.Columns.Count
Range(xRng.Cells(1, i), xRng.Cells(lastRow(i), i)).Cut
ActiveSheet.Paste Destination:=xRng.Cells(xLastRow, 1)
xLastRow = lastRow(1) + 1
Next
End Sub
Function lastRow(col As Long, Optional wks As Worksheet) As Long
If wks Is Nothing Then
Set wks = ActiveSheet
End If
lastRow = wks.Cells(wks.Rows.Count, col).End(xlUp).Row
End Function
The code still needs some improvement as it might loop over all columns espeically if there is no data.
This assumes on all your columns you have data on the 2nd row, to correctly identify the last column.
Option Explicit
Public Sub CombineColumns()
Dim LastColumn As Long, LastRow As Long, LastRowA As Long, i As Long, RngAddress As String
With ActiveSheet
' This assumes you have data on row 2 on all columns
LastColumn = .Cells(2, .Columns.Count).End(xlToLeft).Column
For i = 2 To LastColumn
' Get the last row of Col A on each iteration
LastRowA = .Cells(.Rows.Count, 1).End(xlUp).Row + 1
' Get last row of the Col we're checking
LastRow = .Cells(.Rows.Count, i).End(xlUp).Row
' Get the used range address of the current Col
RngAddress = .Range(.Cells(1, i), Cells(LastRow, i)).Address
' Check if we have blank cells among the rows of the current Col
.Range(.Cells(1, i), Cells(LastRow, i)).Value2 = Evaluate("IF(NOT(ISBLANK(" & RngAddress & "))," & RngAddress & ")")
' Compress data (if there's no empty cells in the current Col the below line will give error, that's the role of err handling)
On Error Resume Next
.Range(.Cells(1, i), Cells(LastRow, i)).SpecialCells(xlCellTypeConstants, 4).Delete xlShiftUp
On Error GoTo 0
' Update the last row in case we compressed data
LastRow = .Cells(.Rows.Count, i).End(xlUp).Row
' Paste data in Col A
.Range(.Cells(1, i), Cells(LastRow, i)).Cut Destination:=.Range("A" & LastRowA)
Next i
Application.CutCopyMode = False
End With
End Sub
Maybe this could be a convenient solution for you :
Sub CombineColumns()
Dim LastRow As Long
LastRow = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
Range("A2:A" & LastRow).Formula = "=B2 & C2 & D2 & E2 & F2 & G2 & H2" 'Insert here the columns you need to be combined
End Sub
Let me know if changes are necessary.

Excel VBA: Loop through cells on another column basing on the first row

I'm currently creating an automation that will separate the fruits for each store. Basically my file looks like below:
What I need to do is to transfer all fruits of Store X and B to column F (all fruits from different stores). The number of stores could grow as well as the fruits.
I have the code below, however, it only gets the first fruit and jump in to the next store already.
Sub test()
Dim i, lastrow As Long
lastrow = ActiveSheet.Cells(Worksheets(1).Rows.Count, "A").End(xlUp).Row
For i = 2 To lastrow
Cells(i, 1).Select
If Cells(i, 1).Value <> "" Then
Cells(i, 6) = Cells(i, 4).Value
End If
Next i
End Sub
I'm thinking to add another lastrow count for the fruits, however, it just continues until the last row of column D.
I suggest the following:
Option Explicit
Public Sub CopyFruitsIntoStores()
Dim ws As Worksheet
Set ws = ThisWorkbook.ActiveSheet 'if this code is for a specific sheet only then better define a sheet like Thisworkbook.Worksheets("NameOfSheet")
Dim LastRow As Long
LastRow = ws.Cells(ws.Rows.Count, "D").End(xlUp).Row 'find last row in col D it is longer than A
Dim iStore As Long 'to count the stores
Dim iRow As Long
For iRow = 2 To LastRow
If ws.Cells(iRow, 1).Value <> vbNullString Then 'if a new store begins
iStore = iStore + 1
'Use following line to write the headers for the stores
ws.Cells(1, 5 + iStore).Value = ws.Cells(iRow, 1).Value & " (Fruits)"
End If
ws.Cells(iRow, 5 + iStore).Value = ws.Cells(iRow, 4).Value
Next iRow
End Sub
Count the stores in iStore and use that store count to determine the destination column.
Also note that you need to determine the LastRow in column D not A. Column D has more entries than A has. If you use A's last row it stops too early.
The following should do what you are requesting, I check column D for the last row instead of A since those are the values you are wanting to transpose:
Sub test()
Dim i As Long, lastrow As Long
lastrow = ActiveSheet.Cells(Worksheets(1).Rows.Count, "D").End(xlUp).Row
For i = 2 To lastrow
Cells(i, 1).Select
If i < 6 Then
Cells(i, 6) = Cells(i, 4).Value
Else
Cells(i, 7) = Cells(i, 4).Value
End If
Next i
End Sub
First Try using below function to get Last Row, this is very handy.
Function LastRow(sh As Worksheet) As Integer
On Error Resume Next
LastRow = sh.Cells.Find(What:="*", After:=sh.Range("A1"), LookAt:=xlPart, LookIn:=xlValues, _
SearchOrder:=xlByRows, SearchDirection:=xlPrevious, MatchCase:=False).Row
On Error GoTo 0
End Function
One more for Last column, just in case for your Future reference.
Function LastColumn(sh As Worksheet) As Integer
On Error Resume Next
LastColumn = sh.Cells.Find(What:="*", After:=sh.Range("A1"), LookAt:=xlPart, LookIn:=xlValues, _
SearchOrder:=xlByColumns, SearchDirection:=xlPrevious, MatchCase:=False).Column
On Error GoTo 0
End Function
Now the Actual working procedure
Sub test()
Dim i as Long, InptClm as integer 'good to define the variable otherwise they will be considered as variant which is at higher memory rank.
Dim LastRow As Integer: LastRow = LastRow(activeworkbook.Sheets("Type sheet name here")
With activeworkbook.Sheets("Type Sheet Name here")
For i = 2 To lastrow
' you don't have to select here as selection slows the performance of codes.
If .Cells(i, 1).Value <> "" Then
' Below code will make the column selection dynamic
inptclm = .rows(1).find(What:=.cells(i,1)&" (Fruits)",After:=Cells(1,1),Lookat:=xlwhole).column()
End If
.Cells(i, inptclm) = Cells(i, 4).Value
Next I
end with
End sub
-- Code not tested, hope it will be able to assist you.
You could use SpecialCells to isolate each blank cells group in column A
Option Explicit
Public Sub test()
Dim iArea As Long
For Each area in Range("D2", Cells(Rows.Count, "D").End(xlUp)).Offset(,-3).SpecialCells(xlCellTypeBlanks).Areas
With area.Offset(-1).Resize(.Rows.Count + 1)
Range("F1").Offset(,iArea).Value = .Cells(1,1).Value
Range("F2").Offset(,iArea).Resize(.Rows.Count).Value = .Value
End With
iArea = iArea + 1
Next
End Sub

insert entire same row beneath when condition was met

I am working on the below code to insert same entire row below/beneath original one. I had a hard time fulfilling the requirement because I am just new to making macros.
I already tried searching but not able to code correctly. It is working to insert an empty row. But what I need is to insert the row that met the condition. Below is the screenshot/code for my macro.
Private Sub CommandButton1_Click()
Dim rFound As Range, c As Range
Dim myVals
Dim i As Long
myVals = Array("LB") '<- starts with 51, VE etc
Application.ScreenUpdating = False
With Range("F1", Range("F" & Rows.Count).End(xlUp))
For i = 0 To UBound(myVals)
.AutoFilter field:=1, Criteria1:=myVals(i)
On Error Resume Next
Set rFound = .Offset(2).Resize(.Rows.Count - 1) _
.SpecialCells(xlCellTypeVisible)
On Error GoTo 0
.AutoFilter
If Not rFound Is Nothing Then
For Each c In rFound
Rows(c.Row + 1).Insert
c.Offset(1, -1).Value = ActiveCell.Value
Next c
End If
Next i
End With
Application.ScreenUpdating = True
End Sub
Sub Test()
Dim rng As Range
Dim rngData As Range
Dim rngArea As Range
Dim rngFiltered As Range
Dim cell As Range
Set rng = Range("A1").CurrentRegion
'Exclude header
With rng
Set rngData = .Offset(1).Resize(.Rows.Count - 1)
End With
rng.AutoFilter Field:=6, Criteria1:="LB"
Set rngFiltered = rngData.Columns("F:F").SpecialCells(xlCellTypeVisible)
rng.AutoFilter Field:=6
For Each rngArea In rngFiltered.Areas
For Each cell In rngArea
'// When inserting a row,
'// iteration variable "cell" is adjusted accordingly.
Rows(cell.Row + 1).Insert
Rows(cell.Row).Copy Rows(cell.Row + 1)
Next
Next
End Sub
Below is the code I just used . Thank you!
Private Sub CommandButton2_Click()
Dim x As Long
For x = ActiveSheet.UsedRange.Rows.CountLarge To 1 Step -1
If Cells(x, "F") = "LB" Then
Cells(x, "F") = "ComP"
Cells(x + 1, "F").EntireRow.Insert
Cells(x, "F").EntireRow.Copy Cells(x + 1, "F").EntireRow
End if
Next x
End Sub

VBA Type Runtime 13 Error

I am wondering if someone can help me with this question. I have written a macro with the objective of deleting selected rows based upon whether or not all cells in a row contain the value "<0.01". The problem is when the program tries to process the if statement it errors out.
Any help would be appreciated.
Sub deleteRows()
Dim rng As Long
Dim FirstCol, LastCol As Long
Set UsedRng = ActiveSheet.UsedRange
FirstCol = UsedRng(1).Column
LastCol = UsedRng(UsedRng.Cells.Count).Column
rng = Application.Selection.Rows.Count
For i = rng To 1 Step -1
if Range(Cells(i, FirstCol), Cells(i, LastCol)) = "<0.01" Then
Rows(i).EntireRow.Delete
End If
Next i
End Sub
New code that i wrote
`Sub for3()
Dim ma, r, c As Range
Dim counter As Long
Dim deletenum As Long
Dim firstcol As Variant
Set ma = Application.Selection
Set r = ma.Rows
Set c = ma.Columns
counter = 0
deletenum = c.Count
firstcol = ma(1).Column
For Each r In ma
For Each c In r
If c.Column = firstcol Then
counter = 0
End If
If c.Text = "<0.01" Then
counter = counter + 1
End If
If counter = deletenum Then
r.EntireRow.Delete
ma.Offset(1, 0).Activate
End If
Next c
Next r
End Sub
`
You can use the Find function per row instead:
Dim FndRng As Range
For i = rng To 1 Step -1
Set FndRng = Range(Cells(i, FirstCol), Cells(i, LastCol)).Find(What:="<0.01", LookIn:=xlValues, LookAt:=xlWhole)
If Not FndRng Is Nothing Then ' find was successful
Rows(i).Delete
End If
Next
Edit 1: check that all cells in row equal to "<0.01".
For i = rng To 1 Step -1
If WorksheetFunction.CountIf(Range(Cells(i, FirstCol), Cells(i, LastCol)), "<0.01") = Range(Cells(i, FirstCol), Cells(i, LastCol)).Cells.Count Then
Rows(i).Delete
End If
Next I
Edit 2:
Option Explicit
Sub t()
Dim Rng As Range
Dim firstCol As Long, LastCol As Long
Dim firstRow As Long, LastRow As Long
Dim i As Long
Dim C As Range
Set Rng = Selection ' only if you realy need to
' calculate the first and last column of the Selection
firstCol = Rng(1).Column
LastCol = Rng.Columns.Count + firstCol - 1
' calculate the first and last Row of the Selection
firstRow = Rng(1).Row
LastRow = Rng.Rows.Count + firstRow - 1
' loop backwards, for the Selection last row, until the first row of the selection
For i = LastRow To firstRow Step -1
' loop through current's row cells
For Each C In Range(Cells(i, firstCol), Cells(i, LastCol))
If C.Value2 <> "<0.01" Then
GoTo ExitLoop
End If
Next C
Rows(i).Delete
ExitLoop:
Next i
End Sub
your test expression might look like:
Join(WorksheetFunction.Transpose(WorksheetFunction.Transpose(Range(Cells(i, FirstCol), Cells(i, LastCol)).Value)), " ") Like "*<0.01*"

Align duplicate column in excel at the same time preserving values present in subsequent column

My data is spreaded in many columns. In that, Column A and Column B has identical name (duplicates), while Column C to Q are values related to column B. I want to align column B to Column A while preserving subsequent values as it is.
NOTE: My question is very much similar to this one "Align identical data in two columns while preserving values in the 3rd in excel"
But in my case I want to preserve more subsequent columns (from C to Q). I played with code given as a solution by #Jeeped in that post but failed.
Can I get any help in this regards,
I have tried following code:
Sub aaMacro1()
Dim i As Long, j As Long, lr As Long, vVALs As Variant
With ActiveSheet
lr = .Cells(Rows.Count, 1).End(xlUp).Row
vVALs = Range("B1:C" & lr)
Range("B1:C" & lr).ClearContents
For i = 1 To lr
For j = 1 To UBound(vVALs, 1)
If vVALs(j, 1) = .Cells(i, 1).Value Then
.Cells(i, 2).Resize(1, 2) = Application.Index(vVALs, j)
Exit For
End If
Next j
Next i
End With
End Sub
I have made an attempt to change range("B1:C" & lr) to range ("B1:Q" & lr), but it didnt work.
After that I have changed .Resize (1,2) to .Resize (1,3), and it copied two subsequent rows but when i inset a code with .Resize (1,4), didn't work.
Hope this edited post helps to answer my question.
With best
Based on the code in the original link, should work with any number of columns ...
Option Explicit
Option Base 1
Sub aaMacro1()
Dim i As Long, j As Long, k As Long
Dim nRows As Long, nCols As Long
Dim myRng As Range
Dim vVALs() As Variant
With ActiveSheet
nRows = .Cells(Rows.Count, 1).End(xlUp).Row
nCols = .Cells(1, Columns.Count).End(xlToLeft).Column
Set myRng = .Range(.Cells(2, 2), .Cells(nRows, nCols))
End With
nRows = nRows - 1
nCols = nCols - 1
vVALs = myRng.Value
myRng.ClearContents
For i = 1 To nRows
For j = 1 To nRows
If vVALs(j, 1) = ActiveSheet.Cells(i + 1, 1).Value Then
For k = 1 To nCols
myRng.Cells(i, k).Value = vVALs(j, k)
Next k
Exit For
End If
Next j
Next i
End Sub
Test input ...
Provides this output ...
you can try this
Option Explicit
Sub AlignDupes()
Dim lRow As Long, iRow As Long
Dim mainRng As Range, sortRange As Range
With ActiveSheet
lRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Set mainRng = .Range("A1:A" & lRow)
Set sortRange = .Range("B1:Q1").Resize(mainRng.Rows.Count)
.Sort.SortFields.Clear
End With
Application.AddCustomList ListArray:=mainRng
With sortRange
.Sort Key1:=.Cells(1, 1), Order1:=xlAscending, Header:=xlNo, OrderCustom:=Application.CustomListCount + 1, MatchCase:=False, Orientation:=xlTopToBottom, DataOption1:=xlSortNormal
iRow = 1
lRow = .Cells(.Rows.Count, 1).End(xlUp).Row
Do While iRow <= lRow
Do While .Cells(iRow, 1) <> .Cells(iRow, 1).Offset(, -1)
.Rows(iRow).Insert
iRow = iRow + 1
lRow = lRow + 1
Loop
iRow = iRow + 1
Loop
End With
Application.DeleteCustomList Application.CustomListCount
End Sub