Find row with multiple search criteria on substrings in VBA - vba

I need to find the row where a cell in column B contains two substrings.
For example these Strings in B1:B3
A string with Cows
Cows and stuff
A string with Chickens
I need to find the row B2where the 2 substrings Cows and shit are present.
What i tried so far:
Find formula that doesent do multiple search criteria. :(
=MATCH(1;INDEX((B:B="Cows")*(B:B="shit"););) that doesent do substrings
A lot other stuff i forgot,
If it is possible i would like a pure VBA solution.
Any ideas on this one?

http://www.mrexcel.com/forum/excel-questions/74933-matching-multiple-criteria-visual-basic-applications.html This is what you are looking for with your MATCH function.

The below will assign all values within column B to an array, and then assess each element of the array to see if it contains the strings "Cows" and "excrement".
To assess the string within the element, we use the InStr() Function.
Sub findStrings()
Dim wb As Workbook, ws As Worksheet
Dim arrValues() As Variant
Dim lrow As Long, i As Long
Set wb = ThisWorkbook
Set ws = wb.Sheets(1)
lrow = ws.Cells(Rows.Count, 2).End(xlUp).Row
arrValues = Range(Cells(1, 2), Cells(lrow, 2))
For i = 1 To UBound(arrValues, 1)
If InStr(1, arrValues(i, 1), "Cows") Then
If InStr(1, arrValues(i, 1), "excrement") Then
MsgBox ("Cell " & Cells(i, 2).Address & " contains both strings.")
Exit Sub
End If
End If
Next i
End Sub
This will only find 1 match containing the strings you specify, if you require further matches then you will need a different solution.

This function returns range that contains all the cells having in its content both words given as parameters:
Public Function findCellsWithWords(firstWord As String, secondWord As String) As Excel.Range
Dim wks As Excel.Worksheet
Dim rng As Excel.Range
Dim rngFirst As Excel.Range
Dim rngSecond As Excel.Range
'--------------------------------------------------
Set wks = Excel.ActiveSheet
Set rng = wks.Columns(2).EntireColumn
Set rngFirst = findAll(rng, firstWord)
Set rngSecond = findAll(rng, secondWord)
Set findCellsWithWords = Excel.Intersect(rngFirst, rngSecond)
End Function
Public Function findAll(rng As Excel.Range, what As Variant) As Excel.Range
Dim rngResult As Excel.Range
Dim found As Excel.Range
Dim firstFound As String
'----------------------------------------------------------------------------
With rng
Set found = rng.Find(what)
Do Until found Is Nothing
If rngResult Is Nothing Then
firstFound = found.Address
Set rngResult = found
Else
Set rngResult = Excel.Union(rngResult, found)
End If
'Find next occurrence.
Set found = .FindNext(found)
If found.Address = firstFound Then Exit Do
Loop
End With
Set findAll = rngResult
End Function

Related

Using VBA Match and Index function

Trying to use match & Index with specified ranges. Does not recognise RefreshDrNumbers in the code.
I am using the Case Function to specify ranges.
Can't seem to make the Case, Match & Index function connect or talk to each other?
The other Forum I've asked is
https://www.mrexcel.com/board/threads/add-ranges-to-match-and-index-functions.1162701/
Private Sub Jobcard_Demands_Click()
If Jobcard_Demands = ("Drawing No`s Update") Then
Dim matchRange As Range
Dim ODict As Object
Dim PartsListLastRow As Long, DestLastRow As Long
Dim LookupRange As Range
Dim i As Integer
Dim wsSource As Worksheet, wsDest As Worksheet
Set wsSource = ThisWorkbook.Worksheets("Parts List")
Set wsDest = ThisWorkbook.Worksheets("Job Card Master")
PartsListLastRow = wsSource.Range("A" & Rows.Count).End(xlUp).Row
DestLastRow = wsDest.Range("A" & Rows.Count).End(xlUp).Row
'This holds the lookup range (including both the lookup key
'column and the value column)
Set matchRange = wsSource.Range("E1:F" & PartsListLastRow)
'Get a dictionary of all the lookup values. The function, as
'defined below, takes the range as well as the relative column
'of the keys and values. In our case, the first column of our
'range has the keys, and the second has the values
Set ODict = GetDictionary(matchRange, 5, 6)
'Below, define the lookup range. In your specific code, this
'varies based on the combobox value, but I think you'll be able
'to figure out how to define it (I'm just hardcoding mine
Set LookupRange = wsDest.Range("A1:A" & DestLastRow)
'Loop over the lookup range
For i = 1 To DestLastRow
'Since the GetPartInfo function handles cases where there isn't a match
' (it returns a blank string), you don't have to use an if/else statement
wsDest.Range("B" & i).Value = GetPartInfo(ODict, wsDest.Range("E" & i).Value)
Next i
End If
End Sub
Private Function GetDictionary(rng As Range, keyCol As Long, valCol As Long) As Object
Dim sht As Worksheet
Dim rCell As Range
Dim ODict As Object
Set sht = rng.Parent
Set ODict = CreateObject("Scripting.Dictionary")
For Each rCell In rng.Columns(keyCol).Cells
If Not ODict.Exists(rCell.Offset(, keyCol - 1).Value) Then
ODict.Add rCell.Offset(, keyCol - 1).Value, rCell.Offset(, valCol - 1).Value
End If
Next rCell
Set GetDictionary = ODict
End Function
'This is just a helper function to de-clutter the main subroutine. Returns an
' empty string in cases where the part doesn't exist in the dictionary
Private Function GetPartInfo(ByRef ODict As Object, sKey As String)
Dim Output As String
Output = ""
If ODict.Exists(sKey) Then
Output = ODict(sKey)
End If
GetPartInfo = Output
End Function
Whenever I'm working with code that performs many lookups over the same range, I tend to package that lookup range into a dictionary. Lookups in a dictionary are highly efficient, so you don't have to worry about the "cost" of the lookup. There is an overhead to populate the dictionary, but this is often recovered as the number of lookups grows.
I took that approach in the below solution. I use helper functions to create the dictionary and to lookup dictionary values. This helps to declutter the main routine. See if you can work with the code below, and adapt it to your solution. I commented it where I felt it would add value, and I think you should be able to adapt to your needs. Write back with any issues.
Sub RefreshStuff()
Dim matchRange As Range
Dim oDict As Object
Dim lastRow As Long
Dim lookupRange As Range
Dim wsDest As Worksheet
'This holds the lookup range (including both the lookup key
'column and the value column)
Set matchRange = Sheets("Parts List").Range("E1:F6")
'Get a dictionary of all the lookup values. The function, as
'defined below, takes the range as well as the relative column
'of the keys and values. In our case, the first column of our
'range has the keys, and the second has the values
Set oDict = GetDictionary(matchRange, 1, 2)
'Below, define the lookup range. In your specific code, this
'varies based on the combobox value, but I think you'll be able
'to figure out how to define it (I'm just hardcoding mine
lastRow = 10
Set wsDest = Sheets("Job Card Master")
Set lookupRange = wsDest.Range("A1:A" & lastRow)
'Loop over the lookup range
For i = 1 To lastRow
'Since the GetPartInfo function handles cases where there isn't a match
' (it returns a blank string), you don't have to use an if/else statement
wsDest.Range("B" & i).Value = GetPartInfo(oDict, wsDest.Range("A" & i).Value)
Next i
End Sub
Private Function GetDictionary(rng As Range, keyCol As Long, valCol As Long) As Object
Dim sht As Worksheet
Dim rCell As Range
Dim oDict As Object
Set sht = rng.Parent
Set oDict = CreateObject("Scripting.Dictionary")
For Each rCell In rng.Columns(keyCol).Cells
If Not oDict.exists(rCell.Offset(, keyCol - 1).Value) Then
oDict.Add rCell.Offset(, keyCol - 1).Value, rCell.Offset(, valCol - 1).Value
End If
Next rCell
Set GetDictionary = oDict
End Function
'This is just a helper function to de-clutter the main subroutine. Returns an
' empty string in cases where the part doesn't exist in the dictionary
Private Function GetPartInfo(ByRef oDict As Object, sKey As String)
Dim output As String
output = ""
If oDict.exists(sKey) Then
output = oDict(sKey)
End If
GetPartInfo = output
End Function

For each range including a variable-problem

I have a problem in a small part of my code : I want it to select the cells starting from c which is a cell meeting a condition that I have defined earlier, to the end of the list. In this range, I want it to copy the first value that exceeds resultat (a value obtained before).
With Worksheets("Feuil1").Range("A2:A5181")
Set c = .Find(Worksheets("Feuil2").Range("A14").Value, LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do
Range(Range(c), Range(c).End(xlDown)).Select
If c Is Nothing Then
GoTo DoneFinding
End If
Loop While c.Address <> firstAddress
End If
DoneFinding:
End With
Dim c As Range
Dim firstAddress As String
Dim resultat As Double
Dim Cel As Range
Dim firstValue As Integer
Dim s1 As String, s2 As String
s1 = Worksheets("Feuil2").Range(c)
s2 = Worksheets("Feuil1").Range(s1).End(xlDown)
Worksheets("Feuil1").Range(s1 & ":" & s2).Select
For Each Cel In Range(s1 & ":" & s2)
If Cel.Value >= resultat Then
firstValue = Cel.Value
firstAddress = Cel.Address
Exit For
End If
Next
Worksheets("Feuil1").firstValue.Copy
Range("C14").Worksheet("Feuil2").PasteSpecial
I get an error for the 2 first lines of the code.
Thanks a lot for your help.
This is my new code, because I realized something is missing.. The SearchRange does not start from row 2, but from the row where the value (a date) is equal to the last date of ws2. I get an error for my For each line. It says Object required.
Edit - New code, object error at rangyrange :
Private Sub CommandButton1_Click()
Dim rangyrange As Range
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim foundRange As Range
Dim searchRange As Range
Dim lastRow As Long
Dim ws1Cell As Range
Dim firstAddress As String
Dim Cel As Range
Dim firstValue As Double
Dim A15Value As Date
Dim firsty As Long
Dim newRange As Range
Dim lastRow2 As Long
Set ws1 = Excel.Application.ThisWorkbook.Worksheets("Feuil1")
Set ws2 = Excel.Application.ThisWorkbook.Worksheets("Feuil2")
A15Value = CDate(ws2.Cells(15, 1).Value)
With ws1
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
lastRow2 = .Cells(.Rows.Count, 2).End(xlUp).Row
Set foundRange = ws1.Range(.Cells(2, 1), .Cells(lastRow, 1))
Set searchRange = foundRange.Find(A15Value, LookIn:=xlValues)
Set rangyrange = ws1.Range(.Cells(searchRange.Row, 1), .Cells(lastRow, 1))
firsty = rangyrange.Rows(1).Row
Set newRange = ws1.Range(.Cells(firsty, 2), .Cells(lastRow2, 2))
End With
For Each ws1Cell In newRange
If ws1Cell.Value >= resultat Then
firstValue = ws1Cell.Value
firstAddress = ws1Cell.Address
Exit For
End If
Next
ws2.Cells(15, 3).Value = firstValue
End Sub
Dim c As Range
Worksheets("Feuil1").Range(Worksheets("Feuil1").Range(c), Worksheets("Feuil1").Range(c).End(xlDown))
You haven't set c to a range, so VBA doesn't understand what you're doing.
Also, I suggest defining a worksheet variable to increase the readability of your code like this:
Set ws = Excel.Application.Worksheets("Feuil1")
And your statement becomes much more legible:
ws.Range(ws.Range(c), ws.Range(c).End(xlDown))
This is not how you reference a range, also, I would suggest never using .Select.
Range(s1 & ":" & s2).Select
This is how you reference a range:
'this is my preferred method of referencing a range
Set someVariable = ws.Range(ws.Cells(row, column), ws.Cells(row, column))
Or...
'this is useful in some instances, but this basically selects a cell
Set someVariable = ws.Range("B2")
Or...
'this references the range A1 to B1
Set someVariable = ws.Range("A1:B1")
Also, as #BigBen pointed out, you cannot set a range like so:
Dim c As Range
s1 = Worksheets("Feuil2").Range(c)
The reasons being:
c hasn't been assigned.
You can't use a range as an input unless it's of the form ws.Range(ws.Cells(row, column), ws.Cells(row, column))
Per your update that includes the assignment for c:
I get an error for the 2 first lines of the code.
This is because you're assigning c before you're declaring c.
You should have all of your Dim statements preceding your actual code (unless you know what you're doing) like so:
Public Sub MySub()
Dim c As Range
Dim firstAddress As String
Dim resultat As Double
Dim Cel As Range
Dim firstValue As Integer
Dim s1 As String, s2 As String
`the rest of your code
End Sub
I would change your Do loop to the following:
With Worksheets("Feuil1").Range("A2:A5181")
Set c = .Find(Worksheets("Feuil2").Range("A14").Value, LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Do While c.Address <> firstAddress
'I'm unsure of the goal here, so I'm ignoring it
Range(Range(c), Range(c).End(xlDown)).Select
If c Is Nothing Then
Exit Do
End If
Loop
End If
End With
Mainly because I hate GoTo statements and because the MS doc for Do loops states to use either Do While or Do Until instead of Loop While or Loop Until
s1 and s2 are strings, so you can't do this:
s1 = Worksheets("Feuil2").Range(c)
s2 = Worksheets("Feuil1").Range(s1).End(xlDown)
I'm assuming you want to get the column and row of c and iterate through that, but the problem is that you're working in 2 different worksheets, which you can't do. I'll assume it's an error and that you want to work on the "Fueil2" worksheet, so here goes:
Dim ws2 As Worksheet
Dim startCell As Range
Dim endCell As Range
Dim foundRange As Range
Set ws2 = Excel.Application.ThisWorkbook.Worksheets("Fueil2")
With ws2
Set startCell = .Cells(c.Row, c.Column)
Set endCell = .Cells(c.End(xlUp).Row, c.Column)
Set foundRange = .Range(.Cells(c.Row, c.Column), .Cells(c.End(xlUp).Row, c.Column))
For Each Cel In foundRange
'yada yada yada
End With
Post-lunch Edit:
It seems that this is a bit misleading because I tested this snippet and it works:
Public Sub test()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim foundRange As Range
Dim searchRange As Range
Dim workRange As Range
Dim foundColumn As Range
Dim ws1LastCell As Range
Dim ws1Range As Range
Dim iWantThis As Range
Set ws1 = Excel.Application.ThisWorkbook.Worksheets("Sheet1")
Set ws2 = Excel.Application.ThisWorkbook.Worksheets("Sheet2")
Set searchRange = ws1.Range("A1:F1")
Set foundRange = searchRange.Find(ws2.Range("C1").Value, LookIn:=xlValues)
With foundRange
'last cell in the ws1 column that's the same column as foundRange
Set ws1LastCell = ws1.Range(ws1.Cells(.Row, .Column), ws1.Cells(ws1.Rows.Count, .Column)).End(xlDown)
'the range you want
Set iWantThis = ws1.Range(foundRange, ws1LastCell)
'check to see if it got what i wanted on ws1
iWantThis.Select
End With
End Sub
New Edit:
Public Sub test()
Dim ws1 As Worksheet
Dim ws2 As Worksheet
Dim c14Value As Double
Dim searchRange As Range
Dim lastRow As Long
Dim ws1Cell As Range
Set ws1 = Excel.Application.ThisWorkbook.Worksheets("Sheet1")
Set ws2 = Excel.Application.ThisWorkbook.Worksheets("Sheet2")
'gets the date
A14Value = CDate(ws2.Cells(14, 1).Value)
With ws1
'gets the last row's number in column A on worksheet 1
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
'selects from A2 to the last row with data in it. this works only if
'there aren't any empty rows between your data, and that's what i'm assuming.
Set searchRange = .Range(.Cells(2, 1), .Cells(lastRow, 1))
End With
For Each ws1Cell In searchRange
If CDate(ws1Cell.Value) >= A14Value Then
'i didnt make a variable for firstValue
firstValue = ws1Cell.Value
'i didnt make a variable for firstAddress
firstAddress = ws1Cell.Address
Exit For
End If
Next
'puts firstValue into cell C14 on ws2
ws2.Cells(14, 3).Value = firstValue
End Sub
Until I see a definition for resultat, I'm assuming it's 100% correctly declared and assigned. hint: You should give us your declaration and assignment of resultat because I can't fully determine if how you defined resultat is an issue.

Match and replace a string from a column in multiple ranges on multiple sheets

I am trying to write a code that will search multiple ranges and match the first half of a string. if the match is true it would them replace the cell in the range with the cell in the column.
I found this code and made some changes to search multiple columns in multiple ranges on different sheets and simply replace if the first part of the string matches.
The other problem I have is that I need it to search part of the string in the cell for example
In the range; 879841.42859-MD_42885
From the column; 879841.42859-MD_43
I want it to match 879841.42859-MD then replace 879841.42859-MD_43885 with 879841.42859-MD_43
' Matchandreplace1 Macro
' Code from stack overflow cut down, no sheets involved.
'
Dim ShSrc As Worksheet, ShTar As Worksheet
Dim SrcLRow As Long, TarLRow As Long, NextEmptyRow As Long
Dim RefList As Range, TarList As Range, RefCell As Range, RefColC
Dim TarCell As Range, TarColC As Range
Dim IsFound As Boolean
Dim ToFind As String
With ThisWorkbook
Set ShSrc = .Sheets("Sheet1")
Set ShTar1 = .Sheets("Sheet2")
Set ShTar2 = .Sheets("Sheet3")
End With
'Get the last rows for each sheet.
SrcLRow = ShSrc.Range("A" & Rows.Count).End(xlUp).Row
TarLRow = ShTar1.Range("A" & Rows.Count).End(xlUp).Row
TarLRow = ShTar2.Range("A" & Rows.Count).End(xlUp).Row
'Set the lists to compare.
Set RefList = ShSrc.Range("A2:A" & SrcLRow)
Set TarList = ShTar1.Range("A2:A" & TarLRow)
Set TarList = ShTar2.Range("A2:A" & TarLRow)
'Initialize boolean, just for kicks.
IsFound = False
'Speed up the process.
Application.ScreenUpdating = False
'Create the loop.
For Each RefCell In RefList
ToFind = RefCell.Value
'Look for the value in our target column.
On Error Resume Next
Set TarCell = TarList.Find(ToFind)
If Not TarCell Is Nothing Then IsFound = True
On Error GoTo 0
'If value exists in target column...
If IsFound Then
'set the value to match and highlight.
TarColC.Value = RefColC.Value
TarColC.Interior.ColorIndex = 4
End If
'Set boolean check to False.
IsFound = False
Next RefCell
Application.ScreenUpdating = True
End Sub
Thanks,
Jerome
A few snips to better describe
The code you have pasted has lot of syntax errors. Excel has got find and replace function which can replace the string it has found. Your requirement is to find a portion of a cell ( from source) and replace the whole cell in target
You have to append a * before and after the find string and it will replace the whole cell. Am assuming that you need to match first 15 letters of the "Find" String
Sub FindReplaceAll1()
Dim sht As Worksheet
Dim fnd As Variant
Dim rplc As Variant
Dim Found As Range
Dim Checkcol As Integer, rowcount As Integer, TcurrentRow As Integer, currentRow As Integer, Targrowcount As Integer
Checkcol = 1 'Denotes A column
Sheets("Sheet1").Select
rowcount = Cells(Rows.Count, Checkcol).End(xlUp).Row
For currentRow = 1 To rowcount
'Find the substring for which you need to match. Am taking first 15 characters.
fnd = Left$(Cells(currentRow, Checkcol).Value, 15)
rplc = Cells(currentRow, Checkcol).Value
For Each sht In ActiveWorkbook.Worksheets
If sht.Name = "Sheet2" Or sht.Name = "Sheet3" Then
'Replace the whole string when a partial match is achieved
sht.Cells.Replace what:="*" & fnd & "*", Replacement:=rplc, LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
End If
Next sht
Next
End Sub

VBA - How to loop

I'm pretty new into this and I got stuck.
If I have a text string in column A (A1:A10) let's say. And I have a macro that looks for a keyword in that string, if it's found I want a word to be entered into column B (B1:B10).
For example A1-Pizza Hut - B1 Pizza, A2 Burger King - B2 Burger.
I got to the point where I can find the keyword, but when I try to do anything that would loop through the range, I always end up getting the same result in B.
Thank you for the answers. I thought I posted my code, but I guess it didn't. Anyways I figured out a way after looking online for the whole day.
Sub one()
Dim food As String, type As String
Dim rng As Range
Dim cel As Range
Set rng = Range("A:A")
For Each cel In rng
food = cel.Value
If InStr(UCase(food), UCase("pizza")) <> 0 Then
type = "Fast food"
Elseif InStr(UCase(food), UCase("burger")) <> 0 Then
type = "Fast food"
Else
type = "Not Fast food"
End If
cel.offset (0, 1).Value = type
Next cel
End Sub
Use a For Each Loop & Split:
Option Explicit
Public Sub Example()
Dim Sht As Worksheet
Dim rng As Range
Set Sht = ActiveWorkbook.Sheets("Sheet2")
For Each rng In Sht.Range("A1", Range("A11").End(xlUp))
rng.Offset(0, 1).Value = Split(rng, " ")(0)
Next
Set Sht = Nothing
Set rng = Nothing
End Sub
This should do what you want:
Sub Find_and_Copy():
Dim keywords() As Variant
keywords = Array("Pizza", "Burger", "Chicken")
Dim endRow As Integer
Dim SearchRng As Range
With Sheets("Sheet1")
endRow = .Cells(Rows.Count, "A").End(xlUp).Row
Set SearchRng = .Range("A1:A" & endRow).Cells
End With
Dim r As Range
Dim firstAddress As String
Dim i As Integer
For i = 0 To UBound(keywords):
With SearchRng
Set r = .Find(keywords(i), LookIn:=xlValues)
If Not r Is Nothing Then
firstAddress = r.Address
Do
Cells(r.Row, "B").Value = keywords(i)
Set r = .FindNext(r)
Loop While Not r Is Nothing And r.Address <> firstAddress
End If
End With
Next
End Sub
It will find all occurrences of each entry in the 'keywords' array that matches cells of column "A" - and of course, set column "B" to that keyword.
Note that say you have an entry like "ala Burger Chicken" it'll put 'Chicken' (which I added to 'keywords' just to keep in the spirit of things) in column B for that row because that's the last thing it did a search for - hence overwriting the previous 'Burger' entry that was in that cell.

How do I delete duplicates between two excel sheets quickly vba

I am using vba and I have two sheets one is named "Do Not Call" and has about 800,000 rows of data in column A. I want to use this data to check column I in the second sheet, named "Sheet1". If it finds a match I want it to delete the whole row in "Sheet1". I have tailored the code I have found from a similar question here: Excel formula to Cross reference 2 sheets, remove duplicates from one sheet and ran it but nothing happens. I am not getting any errors but it is not functioning.
Here is the code I am currently trying and have no idea why it is not working
Option Explicit
Sub CleanDupes()
Dim wsA As Worksheet
Dim wsB As Worksheet
Dim keyColA As String
Dim keyColB As String
Dim rngA As Range
Dim rngB As Range
Dim intRowCounterA As Integer
Dim intRowCounterB As Integer
Dim strValueA As String
keyColA = "A"
keyColB = "I"
intRowCounterA = 1
intRowCounterB = 1
Set wsA = Worksheets("Do Not Call")
Set wsB = Worksheets("Sheet1")
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
Do While Not IsEmpty(wsA.Range(keyColA & intRowCounterA).Value)
Set rngA = wsA.Range(keyColA & intRowCounterA)
strValueA = rngA.Value
If Not dict.Exists(strValueA) Then
dict.Add strValueA, 1
End If
intRowCounterA = intRowCounterA + 1
Loop
intRowCounterB = 1
Do While Not IsEmpty(wsB.Range(keyColB & intRowCounterB).Value)
Set rngB = wsB.Range(keyColB & intRowCounterB)
If dict.Exists(rngB.Value) Then
wsB.Rows(intRowCounterB).delete
intRowCounterB = intRowCounterB - 1
End If
intRowCounterB = intRowCounterB + 1
Loop
End Sub
I apologize if the above code is not in a code tag. This is my first time posting code online and I have no idea if I did it correctly.
I'm embarrassed to admit that the code you shared confused me... anyway for the practice I rewrote it using arrays instead of looping through the sheet values:
Option Explicit
Sub CleanDupes()
Dim targetArray, searchArray
Dim targetRange As Range
Dim x As Long
'Update these 4 lines if your target and search ranges change
Dim TargetSheetName As String: TargetSheetName = "Sheet1"
Dim TargetSheetColumn As String: TargetSheetColumn = "I"
Dim SearchSheetName As String: SearchSheetName = "Do Not Call"
Dim SearchSheetColumn As String: SearchSheetColumn = "A"
'Load target array
With Sheets(TargetSheetName)
Set targetRange = .Range(.Range(TargetSheetColumn & "1"), _
.Range(TargetSheetColumn & Rows.Count).End(xlUp))
targetArray = targetRange
End With
'Load Search Array
With Sheets(SearchSheetName)
searchArray = .Range(.Range(SearchSheetColumn & "1"), _
.Range(SearchSheetColumn & Rows.Count).End(xlUp))
End With
Dim dict As Object
Set dict = CreateObject("Scripting.Dictionary")
'Populate dictionary from search array
If IsArray(searchArray) Then
For x = 1 To UBound(searchArray)
If Not dict.exists(searchArray(x, 1)) Then
dict.Add searchArray(x, 1), 1
End If
Next
Else
If Not dict.exists(searchArray) Then
dict.Add searchArray, 1
End If
End If
'Delete rows with values found in dictionary
If IsArray(targetArray) Then
'Step backwards to avoid deleting the wrong rows.
For x = UBound(targetArray) To 1 Step -1
If dict.exists(targetArray(x, 1)) Then
targetRange.Cells(x).EntireRow.Delete
End If
Next
Else
If dict.exists(targetArray) Then
targetRange.EntireRow.Delete
End If
End If
End Sub
Edit: Because it bothered me, I reread the code that you provided. It confuses me because it isn't written the way I'd have expected and fails unless you're checking string values only. I've added comments to indicate what it's doing in this snippet:
'Checks to see if the particular cell is empty.
Do While Not IsEmpty(wsA.Range(keyColA & intRowCounterA).Value)
'Stores the cell to a range for no good reason.
Set rngA = wsA.Range(keyColA & intRowCounterA)
'Converts the value of the cell to a string because strValueA is a string.
strValueA = rngA.Value
'Checks to see if the string is in the dictionary.
If Not dict.Exists(strValueA) Then
'Adds the string to the dictionary.
dict.Add strValueA, 1
End If
Then later:
'checks the value, not the value converted to a string.
If dict.Exists(rngB.Value) Then
This fails because the Scripting Dictionary does not consider a double to equal a string, even if they would be the same if the double were converted to a string.
Two ways to fix the code you posted, either change the line I just showed to this:
If dict.Exists(cstr(rngB.Value)) Then
Or you can change Dim strValueA As String to Dim strValueA.
Because I had the time, here's a rewrite forgoing the Dictionary and instead using a worksheet function. (Inspired by the Vlookup comment). I'm not sure which would be faster.
Sub CleanDupes()
Dim targetRange As Range, searchRange As Range
Dim targetArray
Dim x As Long
'Update these 4 lines if your target and search ranges change
Dim TargetSheetName As String: TargetSheetName = "Sheet1"
Dim TargetSheetColumn As String: TargetSheetColumn = "I"
Dim SearchSheetName As String: SearchSheetName = "Do Not Call"
Dim SearchSheetColumn As String: SearchSheetColumn = "A"
'Load target array
With Sheets(TargetSheetName)
Set targetRange = .Range(.Range(TargetSheetColumn & "1"), _
.Range(TargetSheetColumn & Rows.Count).End(xlUp))
targetArray = targetRange
End With
'Get Search Range
With Sheets(SearchSheetName)
Set searchRange = .Range(.Range(SearchSheetColumn & "1"), _
.Range(SearchSheetColumn & Rows.Count).End(xlUp))
End With
If IsArray(targetArray) Then
For x = UBound(targetArray) To 1 Step -1
If Application.WorksheetFunction.CountIf(searchRange, _
targetArray(x, 1)) Then
targetRange.Cells(x).EntireRow.Delete
End If
Next
Else
If Application.WorksheetFunction.CountIf(searchRange, targetArray) Then
targetRange.EntireRow.Delete
End If
End If
End Sub