Compare two Columns and format matching cells with different colors - excel

I would appreciate your help with the following:
I would like to compare two columns, let us say Column A and Column B, **looking for duplicates**.
If a value in Column A has a match value in Column B, I would like to format the cells of the same duplicate value with the color (the colors are random and different for each match).
This is if `A12 = B30`, the color will be red. And if `A20 = B1`, the color is green and so on.
If there is no match just leave it as it.
That was only an example for red and green. let say you have two columns (A and B).
A1 = 1000
A2 = 2000
A3 = 3000
A4 = 4000
A5 = 5000
A6 = 6000
A7 = 7000
A8 = 8000
A9 = 9000
B1 = 1500
B2 = 9000
B3 = 5000
B4 = 3500
B5 = 7500
B6 = 1000
B7 = 4000
So you have several matches and I need each match to be in random different colors. For example:
A1 = B6 –> They will be colored/highlighted in green
A4 = B7 –> They will be colored/highlighted in red
A5 = B3 –> They will be colored/highlighted in yellow
A9 = B2 –> They will be colored/highlighted in pink
The colors will be different for any match and the non-match will be color less or no change.
I wish this will explain the question and this has to be using excel.
{
Sub UsingCollection()
Dim cUnique As Collection
Dim Rng As Range
Dim Cell As Range
Dim sh As Worksheet
Dim vNum As Variant for at
Dim LstRw As Long
Dim c As Range, clr As Long, x
Set sh = ActiveSheet
With sh
LstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
Set Rng = .Range("A1:B" & LstRw)
Set cUnique = New Collection
Rng.Interior.ColorIndex = xlNone
clr = 3
On Error Resume Next
For Each Cell In Rng.Cells
cUnique.Add Cell.Value, CStr(Cell.Value)
Next Cell
On Error GoTo 0
For Each vNum In cUnique
For Each c In Rng.Cells
If c = vNum Then
x = Application.WorksheetFunction.CountIf(Rng, vNum)
If x > 1 Then c.Interior.ColorIndex = clr "error here: the code runs fine for around 50 lines then it is stoppedand gives error and pointing to this line"
//Error shows in pop window: Run-time error 'g': Subscript out of range
End If
Next c
clr = clr + 1
Next vNum
End With
End Sub
}

This is an adjusted code from my answer here.
https://stackoverflow.com/a/33798531/1392235
Loop through the cells to find the unique values, then loop through the unique values to color the duplicates.
Sub UsingCollection()
Dim cUnique As Collection
Dim Rng As Range
Dim Cell As Range
Dim sh As Worksheet
Dim vNum As Variant
Dim LstRw As Long
Dim c As Range, clr As Long, x
Set sh = ActiveSheet
With sh
LstRw = .Cells(.Rows.Count, "A").End(xlUp).Row
Set Rng = .Range("A1:B" & LstRw)
Set cUnique = New Collection
Rng.Interior.ColorIndex = xlNone
clr = 3
On Error Resume Next
For Each Cell In Rng.Cells
cUnique.Add Cell.Value, CStr(Cell.Value)
Next Cell
On Error GoTo 0
For Each vNum In cUnique
For Each c In Rng.Cells
If c = vNum Then
x = Application.WorksheetFunction.CountIf(Rng, vNum)
If x > 1 Then c.Interior.ColorIndex = clr
End If
Next c
clr = clr + 1
Next vNum
End With
End Sub
Results
Sample Workbook
EDIT:
Using colorindex limits us to 56 colors, if we use RGB we can increase that. Edit this part of the code, you will have to play with the values get the color variances you like.
If x > 1 Then c.Interior.Color = 1000000 + clr * 100
End If
Next c
clr = clr + 255

Related

Excel highlight cells with the same value in colors with VBA

Excel highlight cells with the same value in colors
I need a macro that will color all duplicate cells with colors,
I need to color the cells in different colors, to Cell A2 and Cell A3 can have the same value like 50, and Cell A4 and A5 can have the value of 60, And Cell A7,A8 and A9 can have tha value of 40, or Cell A11, A15 and A20 can have tha value of 250.
I need the colors to not be the same if the value is different so Cells A2 and A3 can be yellow if the value is duplicate , then Cell A4 and A5 can be Orange, Cells A7, A8 and A9 can be yellow.
The problem is that it I can have an Excel files from 10 cells to 600 cells, So It can take forever to do manually.
I have a macro that can color in this way, but I need to be able to read tha value i the colored cells, something my macro can't do.
Is it possible to do something like this in VBA?
VBA Code:
Dim ws As Worksheet
Dim clr As Long
Dim rng As Range
Dim cell As Range
Dim r As Range
Set ws = ThisWorkbook.Sheets(ActiveSheet.Name)
Set rng = ws.Range("A2:a" & Range("A" & ws.Rows.Count).End(xlUp).Row)
With rng
Set r = .Cells(.Cells.Count)
End With
rng.Interior.ColorIndex = xlNone
clr = 3
For Each cell In rng
If Application.WorksheetFunction.CountIf(rng, cell) > 1 Then
'addresses will match for first instance of value in range
If rng.Find(What:=cell, LookAt:=xlWhole, MatchCase:=False, After:=r).Address = cell.Address Then
'set the color for this value (will be used throughout the range)
cell.Interior.ColorIndex = clr
clr = clr + 1
Else
'if not the first instance, set color to match the first instance
cell.Interior.ColorIndex = rng.Find(What:=cell, LookAt:=xlWhole, MatchCase:=False, After:=r).Interior.ColorIndex
End If
End If
Next
End Sub
If all you want to do is have an alternating color like in the picture, you only need to change the row clr = clr + 1 to something like the following.
If clr = 44 Then
clr = 45
Else
clr = 44
End If
Those are an estimation of the color in the picture. You also want to change clr = 3 to clr = 44 or whatever color you and up using.
If the numbers are sorted ascending or descending (like in your image) then you can do this much faster than using the find method.
Option Explicit
Public Sub ColorDuplicatesAlternate()
Dim ws As Worksheet ' define your sheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Dim LastRow As Long ' find last used row
LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
Dim DataRange As Range ' read data range
Set DataRange = ws.Range("A1", "A" & LastRow + 1)
Dim DataValues() As Variant ' read data into array for fast processing
DataValues = DataRange.Value
Dim iStart As Long
iStart = 1
Dim BlockValue As Variant
Dim IsEven As Boolean
Dim EvenBlocks As Range
Dim OddBlocks As Range
Dim CurrentBlock As Range
Dim iRow As Long
For iRow = LBound(DataValues) + 1 To UBound(DataValues) ' loop through all data and find blocks, collect them in even and odd numbered blocks for alternate coloring
If BlockValue <> DataValues(iRow, 1) Then
If iRow - iStart > 1 Then
Set CurrentBlock = DataRange.Cells(iStart, 1).Resize(RowSize:=iRow - iStart)
If IsEven Then
If EvenBlocks Is Nothing Then
Set EvenBlocks = CurrentBlock
Else
Set EvenBlocks = Union(EvenBlocks, CurrentBlock)
End If
Else
If OddBlocks Is Nothing Then
Set OddBlocks = CurrentBlock
Else
Set OddBlocks = Union(OddBlocks, CurrentBlock)
End If
End If
IsEven = Not IsEven
End If
iStart = iRow
BlockValue = DataValues(iRow, 1)
End If
Next iRow
' color all even and odd blocks alternating
EvenBlocks.Interior.Color = vbRed
OddBlocks.Interior.Color = vbGreen
End Sub

Read the colour of multiple cells and depending on the colour, return a colour to another cell

I want to read through multiple cells in a row and depending if they are all formatted green, turn a separate cell green.
If one cell in the row is either red or has no colour the cell will remain with red or no colour, then loop through my table to read each row and return a format in one column of cells.
And when I click my update button which brings new data into the table, the column of cells will reset to no colour then be formatted.
[![enter image description here][1]][1]
Sub CS_Click()
Range("D6:D37").Interior.ColorIndex = 0
Dim Range1 As Range
Dim Range2 As Range
For RR = 1 To 33
For CC = 1 To 31
Set Range1 = Cells(RR + 5, CC + 6)
Set Range2 = Cells(RR + 5, CC + 3)
If Range1.Interior.ColorIndex = 0 Then
Range2.Interior.ColorIndex = 0
ElseIf Range1.Interior.ColorIndex = 38 Then
Range2.Interior.ColorIndex = 38
ElseIf Range1.Interior.ColorIndex = 50 Then
Range2.Interior.ColorIndex = 50
End If
Next
Next
End Sub
I think you could use something like the following. This will loop through a range and test each row in the range for the ColorIndex of that row. It will then update a destination row with the ColorIndex of your choice
Sub CS_Click()
Dim rng As Range, RowRng As Range
Dim c As Range
Dim RowNo As Long
Dim ClrIndex As Long
Dim ChangeClr As Boolean
' The range of your source data
Set rng = ActiveSheet.Range("G6:AM37")
For Each c In rng.Columns(1).Cells
ClrIndex = -4142
ChangeClr = False
RowNo = c.Row - rng.Cells(1).Row + 1
On Error Resume Next
Set RowRng = Nothing
Set RowRng = rng.Rows(RowNo).SpecialCells(xlCellTypeConstants)
On Error GoTo 0
If Not RowRng Is Nothing Then
Select Case RowRng.Interior.ColorIndex
' Case 50
Case 50
ClrIndex = 50
ChangeClr = True
' Blank rows
Case -4142
ChangeClr = False
' Others not defined, Null (Mixed color rows) and color 38 rows
Case Else:
ClrIndex = 38
ChangeClr = True
End Select
If ChangeClr = True Then
' Update the 'rng.Coloumns.Count + 1' with the offset of your destination cell
c.Offset(0, -3).Interior.ColorIndex = ClrIndex
End If
End If
Next c
End Sub
I think your code can be simplified to:
Sub CS_Click()
Range("D6:D37").Interior.ColorIndex = 0
For RR = 1 To 33
Set Range2 = Cells(RR + 5, 4)
For CC = 1 To 31
Set Range1 = Cells(RR + 5, CC + 6)
c = Range1.Interior.ColorIndex
If c = 38 Or c = 50 Then
Range2.Interior.ColorIndex = c
Exit For ' remove this line as necessary
End If
Next
Next
End Sub
If you leave the Exit For line in, then the colour in column D will change based on the first pink or green cell it gets to. If you remove it, it will change the colour on each pink or green cell - resulting in column D representing the last green or pink colour it detected.

Find a range address #2

So because I wasn't specific with my previous question I need your help again.
Basically, I asked if there's a way to find a range between some value/cells, because I was sure that when i will get that range this below will work (so I can select lets say "headers" of the columns with all the data below:
totalRange(Selection, Selection.End(xlDown)).Select
So one of you came up with help and provide code below, which is working just fine, but i'm not sure if I can use it in my case. Because as I said, what im trying to do is to first find a range between two cells in firstrow and then select all the data below with it. Something like on screenshot below.
I want to find Col7 and Col12 and then select the whole range below.
The problem is this Col7/Col12 range might start from different column in each file.
https://ibb.co/gtuvEb
Sub RangeBetween()
Dim totalRange As Range
Dim c1 As Long, c2 As Long
Dim r1 As Long, r2 As Long
r1 = 0
r2 = 0
c1 = 1
c2 = 1
With Worksheets("Sheet1") 'Change to your worksheet
c1 = 1
Do Until Name = "A"
Name = Cells(1, c1)
c1 = c1 + 1
Loop
c1 = c1 - 1
c2 = 1
Do Until Name = "B"
Name = Cells(1, c2)
c2 = c2 + 1
Loop
c2 = c2 - 1
On Error Resume Next
r1 = Application.WorksheetFunction.Match("A", .Columns(c1), 0)
r2 = Application.WorksheetFunction.Match("B", .Columns(c2), 0)
On Error GoTo 0
If r1 > 0 And r2 > 0 Then
Set totalRange = .Range(.Cells(r1, c1), .Cells(r2, c2))
totalRange.Select
Else
MsgBox "One or both items not found in range"
End If
End With
End Sub
Thanks for any suggestions.
Sub RangeBetween()
Dim totalRange As Range
Dim c1 As Long, c2 As Long
Dim r1 As Long
With Worksheets("Sheet1") 'Change to your worksheet
On Error Resume Next
'Find the Columns
c1 = Application.WorksheetFunction.Match("Col7", .Rows(1), 0)
c2 = Application.WorksheetFunction.Match("Col12", .Rows(1), 0)
On Error GoTo 0
If c1 > 0 And c2 > 0 Then
'Find last row with data
r1 = .Cells(.Rows.Count, c2).End(xlUp).Row
'Set the range to the whole
Set totalRange = .Range(.Cells(1, c1), .Cells(r1, c2))
totalRange.Select
Else
MsgBox "One or both items not found in range"
End If
End With
End Sub
It seems that you try to look up certain values in the headers and select the ones between those columns. If I understood correctly, your question this can help you.
Dim ws As Worksheet
Set ws = ThisWorkbook.Sheets("your sheet")
Dim header1 As Range, header2 As Range
On Error Resume Next
Set header1 = ws.Rows(1).Find(what:="your header value 1", LookIn:=xlValues,
lookat:=xlWhole)
Set header2 = ws.Rows(1).Find(what:="your header value 2", LookIn:=xlValues,
lookat:=xlWhole)
On Error GoTo 0
If Not header1 Is Nothing And Not header2 Is Nothing Then
Range(header1,
header2).EntireColumn.SpecialCells(xlCellTypeConstants).Select
Else:
MsgBox "Header not fount"
End If

Find a range address

I want to select some range based on cells value, as they might be each time in different column.
So my first thought was something like below, but I'm not sure if that's the right way?
Sub RangeBetween()
Dim rng1 As Range, rng2 As Range
Dim totalRange As Range
Dim c1, c2 As Integer
c1 = 1
Do Until Name = "A"
Name = Cells(1, c1)
c1 = c1 + 1
Loop
someA= c1 - 1
c2 = 1
Do Until Name = "B"
Name = Cells(1, c2)
c2 = c2 + 1
Loop
someB= c2 - 1
Set rng1 = Range("???")
Set rng2 = Range("???")
Set totalRange = Range(rng1.Address & ":" & rng2.Address)
totalRange .Select
End Sub
Thanks
Or you can use Match()
Sub RangeBetween()
Dim totalRange As Range
Dim c1 As Long, c2 As Long
c1 = 0
c2 = 0
With Worksheets("Sheet1") 'Change to your worksheet
On Error Resume Next
c1 = Application.WorksheetFunction.Match("A", .Rows(1), 0)
c2 = Application.WorksheetFunction.Match("B", .Rows(1), 0)
On Error GoTo 0
If c1 > 0 And c2 > 0 Then
Set totalRange = .Range(.Cells(1, c1), .Cells(1, c2))
totalRange.Select
Else
MsgBox "One or both items not found in range"
End If
End With
End Sub

Increment value if another cell is populated vba

I am trying to create some automatism on my excel database.
In this case increment a value if another cell is populated.
Example:
Start a count starting at A21 if B21 contains a number or text.
The count will stop if there is no value on the B adjacent cell.
A B
21 1 Text 1
22 2 Text 2
23 3 Text 3
24
25
So far I got this:
Sub Macro1()
Dim r1 As Range, r2 As Range, cell As Range, mynumber As Long
Set r1 = Range("B21:B2642")
Set r2 = Range("A21:A2642")
mynumber = 1
For Each cell In r1
If cell.Value <> "" Then
cell.Value("A21:A2642") = mynumber
mynumber = mynumber + 1
End If
Next
End Sub
Bests
Work with this,
Sub Button1_Click()
Dim rw As Long, rng As Range, c As Range
rw = 2642
Set rng = Range("B21:B" & rw)
For Each c In rng.Cells
If c <> "" Then
If c.Row = 21 Then
c.Offset(, -1) = 1
Else
c.Offset(, -1) = c.Offset(-1, -1) + 1
End If
End If
Next c
End Sub

Resources