Excel remove only unique cells - vba

I have been struggling with coming up with a solution to deleting all cells that are unique across my excel sheet.
I have an excel sheet that look something like this:
cat dog shrimp donkey
dog human wale
wale bear
dog donkey shrimp human wale
and I would like to now remove all values that are unique amongst all cells (so here that would be removing cat and bear) while keeping all the order of all the rows etc. intact.
I also have a few rows that are completely empty (but that I can't delete).
I have tried the following macro, but it's my first vba macro (and I know it is stupidly inefficient :) ) For some reason it doesn't delete anything whereas I can't see the logic error.
Code:
Sub doit()
Dim rng As Range
Dim rngtoCheck As Range
Dim cell As Range
Dim isCellUnique As Boolean
Dim cellToCheck As Range
Set rng = Range("A1:Z20")
Set rngtoCheck = Range("A1:Z20")
For Each cell In rng
isCellUnique = True
For Each cellToCheck In rngtoCheck
If cell.Value = cellToCheck.Value AND cell.row <> cellToCheck.row Then
isCellUnique = False
End If
Next cellToCheck
If isCellUnique = True Then
cell.ClearContents
End If
Next cell
End Sub
The idea is that I loop through the entire range and for each cell I check if any other cell in the range has the same value, but is not on the same row. If both check out I keep the value, otherwise I clear the cell.
What am I doing wrong?

You can use Application.WorksheetFunction.CountIf to check if the cell is repeated more than once?
Is this what you are trying?
Tried And Tested
Sub doit()
Dim rng As Range, aCell As Range
'~~> Change this to the relevant sheet
Set rng = ThisWorkbook.Sheets("Sheet1").Range("A1:Z20")
For Each aCell In rng
If Not Len(Trim(aCell.Value)) = 0 Then
'~~> Check if word occurs just once
If Application.WorksheetFunction.CountIf(rng, aCell.Value) = 1 Then
MsgBox aCell.Value & " is unique"
'
'~~> Do what you want here
'
End If
End If
Next aCell
End Sub

Related

Highlighting empty cells within columns

I am trying to highlight empty cells in columns K,L,M.
I tried the below code
Sub highlight()
Dim myRange As Range, cel As Range
Set myRange = Sheet1.Range("K:M")
For Each cel In myRange
If Trim(cel.Value) = "" Then cel.Interior.ColorIndex = 3
Next cel
End Sub
Looking to highlight all the empty cells.
Try:
Sub Color_blank_cells()
'declare variables
Dim ws As Worksheet
Dim ColorRng As Range
Set ws = Worksheets("WorksheetName")
Set ColorRng = ws.Range("B3:C9")
'color blank cells'
ColorRng.SpecialCells(xlCellTypeBlanks).Interior.Color = RGB(220, 230, 241)
End Sub
Your code appears to work fine, it highlights all the empty cells red. The problem is that you have no way to break out of your loop when you reach the end of your data, the code will continue to highlight empty cells all the way to the end of the sheet (to row 1,048,576) which will likely cause Excel to hang.
You could find the last row of data and break out of the loop when this row is reached. The below limits the loop to the length of column "K" (assumes all columns have the same length).
Sub highlight()
Dim myRange As Range, cel As Range
Set myRange = Sheet1.Range("K:M")
n = Sheets("Sheet1").Range("K" & Sheets("Sheet1").Rows.Count).End(xlUp).Row
For Each cel In myRange
If cel.Row > n Then Exit For
If Trim(cel.Value) = "" Then cel.Interior.ColorIndex = 3
Next cel
End Sub

Loop Through Non Blank Cells

I just want to know how to loop through the non blank cells on Column A. What I'm trying to do is copy the contents on [A1:B1] to be added on top of each non blank cells on Column A. So far I have counted the non blank cells on column A but I'm stuck. I know that an Offset function should be used for this.
Here's my code so far:
Dim NonBlank as Long
NonBlank = WorksheetFunction.CountA(Worksheet(1).[A:A])
For i = 1 to NonBlank
[A1:B1].Copy Offset(1,0). "I'm stuck here"
Next i
If you are trying to fill the headers for each Product, try this...
Sub FillHeaders()
Dim lr As Long
Dim Rng As Range
lr = ActiveSheet.UsedRange.Rows.Count
Application.ScreenUpdating = False
On Error Resume Next
Range("A1:B1").Copy
For Each Rng In Range("A3:A" & lr).SpecialCells(xlCellTypeConstants, 2).Areas
If Rng.Cells(1).Value <> Range("A1").Value Then
Rng.Cells(1).Offset(-1, 0).PasteSpecial xlPasteAll
End If
Next Rng
Application.CutCopyMode = 0
Application.ScreenUpdating = True
End Sub
As example to simulate the effect of Ctrl-Down from Cell A1 and display the Address, Value in the Immediate Window:
Sub HopToNextNonBlankCellBelow()
Dim oRng As Range
Set oRng = Range("A1")
Debug.Print "Cell Address", "Cell Value"
Do
Set oRng = oRng.End(xlDown)
If Not IsEmpty(oRng) Then Debug.Print oRng.Address(0, 0), oRng.Value
Loop Until oRng.Row = Rows.Count
Set oRng = Nothing
End Sub
Try this... I've (probably) overcounted the rows at 1000, but it likely won't make a difference with your performance. If you wanted to be more precise, there are hundreds of articles on how to find the last row of a range. As for the Offset function, it references a cell in relation to the one we're looping through. In the example below, the code is saying cell.offset(0,1) which means one cell to the right of the cell we are currently looping through. A clearer (less loopy!) example would be if you typed: Range("A10").offset(0,1) it would be the same as typing Range("B10")
Dim Cell As Range
For Each Cell In Range("A2:A1000").Cells
If Not IsEmpty(Cell) Then
Cell.Offset(0, 1).Value = Cell.Value
End If
Next Cell

Looping through a column to move cells with font size 10 down one row

I have section title cells set at 10 pt font while all other data is set at 9 point font in column A. I am trying to write a vba macro to loop through column A to move each title cell down one row(because the csv leaves a blank cell below them) then move on to the next title cell in the column. Here is my attempt but I'm not sure what I'm doing wrong here.
Sub FontSpacing()
Dim Fnt As Range
For Each Fnt In Range("A8:A5000")
If Fnt.Font.Size = "10" Then
ActiveCell.Cut Destination:=ActiveCell.Offset(",1")
End If
Next
Try this
Sub FontSpacing()
Dim r As Range
For Each r In ThisWorkbook.Worksheets("Sheet1").Range("A8:A5000")
If r.Font.Size = 10 Then
r.Offset(1,0).Value = r.Value
r.Value = vbNullString
End If
Next r
End Sub
The issues:
Offset(",1") shouldn't have the speech marks. I.e. it should be Offset(0,1). In fact, if you want to paste to the row below, then it should be Offset(1,0).
Avoid using ActiveCell. It's not the cell that is looping through your range, it's just the cell that was active on the worksheet when you ran the sub.
Fnt is a bad name for a range, it's probably the reason you got confused. When declaring (dimensioning) a range, try to give it a name that makes it clear you're working with a range.
Extra:
Fully qualify your range reference to avoid an implicit reference to the ActiveSheet e.g. ThisWorkbook.Worksheets("Sheet1").Range("A1").
Avoid cutting an pasting by setting the Value directly
Your indentation is out, which makes it look like a complete Sub, but it's missing the End Sub.
Not sure if you meant 1 Row below or 1 Column right so:
To shift 1 Column:
Sub FontSpacing()
Dim rng As Range, cell As Range
Set rng = Range("A1:A5000")
For Each cell In rng
If cell.Font.Size = "10" Then
cell.Offset(0, 1).Value = cell.Value
cell.Clear
End If
Next
End Sub
To shift 1 Row:
Sub FontSpacing()
Dim rng As Range, cell As Range
Set rng = Range("A1:A5000")
For Each cell In rng
If cell.Font.Size = "10" Then
a = cell.Row + 1
Rows(a & ":" & a).Insert Shift:=xlDown, CopyOrigin:=1
cell.Offset(1, 0).Value = cell.Value
cell.Offset(1, 0).Font.Size = "11"
cell.Clear
End If
Next
End Sub

Find to cells in range with specific colors and add comments

I am trying to create a macro that will search a column of text (A:A) for a specific interior color. In this case the interior color is 55. Normally I'd create a range of A1:A101 but the data that is added changes daily so there may be more or less.
Essentially once the macro identifies the cells with the colors I want the macro to add a comment to the cell. Something simple like "Hello World!".
So far this is what I have:
Sub AddCommentBasedOnColor()
Dim rng As Range, cell As Range
Set rng = Range("G:G")
Application.ScreenUpdating = False
Application.Calculation = xlManual
For Each cell In rng
If cell.Interior.ColorIndex = 55 Then
If rng.Comment Is Nothing Then rng.AddComment
rng.Comment.Text "Possible Aux Stacking"
End
End If
Next cell
Application.ScreenUpdating = True
Application.Calculation = xlAutomatic
End Sub
The problem that I am running into is that when I am running the code, the comment portion does not work at all. No comments are made and for some reason I get a debug code but did not have one before. Not sure what I did that changed it.
Additionally, when I remove the commenting section of this code it does take some time to run, any assistance with shortening that length of time would be appreciated as well.
Your code has logical problems.
With rng.AddComment you try setting a comment to the whole column G as rng is the whole column G. This is not possible.
And your inner If statement works as follows:
...
If rng.Comment Is Nothing Then rng.AddComment
rng.Comment.Text "Possible Aux Stacking"
End
...
If rng.Comment Is Nothing Then rng.AddComment. Here the If ends. The next program row is processing ever without additional conditions and the End then ends the Sub at this point.
To shortening the processing time you have not to run over all rows in column G. This is possible by calculation the last used row. How to do this differs on how you define the last used row. Since you are working with the cell's interior, I have defined the last used row as the last row having cells with not default content of empty cells.
Sub AddCommentBasedOnColor()
Dim rng As Range, cell As Range, lastUsedRow As Long
With ActiveSheet
lastUsedRow = .UsedRange.Rows(.UsedRange.Rows.Count).Row
Set rng = .Range("G1:G" & lastUsedRow)
For Each cell In rng
If cell.Interior.ColorIndex = 55 Then
If cell.Comment Is Nothing Then
cell.AddComment
cell.Comment.Text "Possible Aux Stacking"
End If
End If
Next cell
End With
End Sub
You can use Find rather than loop through each cell:
Sub AddCommentBasedOnColor()
Dim rng1 As Range
Dim rng2 As Range
Dim strFirst As String
Application.FindFormat.Interior.ColorIndex = 55
Set rng1 = Columns("G:G").Find(What:="", SearchDirection:=xlNext, SearchFormat:=True)
If Not rng1 Is Nothing Then
strFirst = rng1.Address
Set rng2 = rng1
Do
Set rng2 = Columns("G:G").Find(What:="", After:=rng2, SearchDirection:=xlNext, SearchFormat:=True)
If rng2.Comment Is Nothing Then
rng2.AddComment
rng2.Comment.Text "Possible Aux Stacking"
End If
Loop Until rng2.Address = strFirst
End If
End Sub

Remove Duplicates from Random Cells using Excel VBA

I have an excel sheet where I've duplicate values in difference cells. BUT the catch here is all those cells are not adjacent to one another. I'll randomly select those cells manually from the sheets & want to remove the duplicates.
In below screenshot I've selected random cells with value "test". I would like to remove the duplicates from selected cells.
Apologies : Adding possible scenario. Need only first occurrence of any repetitive cells. Remove remaining occurrences. It means it should give A1=TEST & B6=WEST. all other cell values should be removed.
Assuming that you have already made the random selection:
Sub dural()
Dim v As Variant, r As Range
v = ActiveCell.Text
addy = ActiveCell.Address
For Each r In Selection
If Not addy = r.Address Then
If r.Value = v Then
r.ClearContents
End If
End If
Next r
End Sub
Just for fun, here's a non-looping version. It does wipe out the ActiveCell's value and then reassign it, which worked in all situations in my limited testing:
Sub RemoveAllSelectionCellsExceptActiveCell()
Dim ActiveCellValue As Variant
ActiveCellValue = ActiveCell.Formula
Selection.Clear
ActiveCell.Formula = ActiveCellValue
End Sub
EDIT: Response to your edited question
This relies on the fact that adding a duplicate to a collection generates an error. If that happens, the cell in question is added to a range of cells to delete. Note that it will treat a cell with "=2" as different from a cell with "2":
Sub RemoveAllSelectionCellsExceptActiveCell2()
Dim cell As Excel.Range
Dim collDupes As Collection
Dim DupeCells As Excel.Range
Set collDupes = New Collection
For Each cell In Selection.Cells
On Error Resume Next
collDupes.Add cell.Formula, cell.Formula
If Err.Number <> 0 Then
If DupeCells Is Nothing Then
Set DupeCells = cell
Else
Set DupeCells = Union(DupeCells, cell)
End If
End If
On Error GoTo 0
Next cell
DupeCells.Clear
End Sub
And another...
If you want to clear the cells' contents and formatting and leave the cursor in the ActiveCell with no selected cells highlighting.
Note, when you make your selection, it will be the last cell visited that is the ActiveCell whose contents will remain, and remain selected.
Option Explicit
Sub remSelDup()
Dim ac As Range, c As Range
Set ac = ActiveCell
For Each c In Selection
If c = ac And c.Address <> ac.Address Then
c.Clear
End If
Next c
ac.Select
End Sub
There should be more than a few Find/FindNext examples on this site but here's another one.
Dim fnd As Range, fcl As Range, searchTerm As Variant
With ActiveSheet
Set fcl = ActiveCell
searchTerm = fcl.Value
Set fnd = .Cells.Find(What:=searchTerm, After:=fcl, LookIn:=xlValues, LookAt:= _
xlWhole, SearchDirection:=xlNext, MatchCase:=False, SearchFormat:=False)
Do While fcl.Address <> fnd.Address
fnd.ClearContents
Set fnd = .Cells.FindNext(After:=fcl)
Loop
End With