Macro to Find Two Columns

miva0601

New Member
Joined
Mar 31, 2015
Messages
33
I receive a file each month where I need to do a find and replace on two columns.
I highlight both columns and find and replace
find "_GUAR" replace all with nothing
find"," replace all with a space
find "HEALTHMART" replace all with HM
find "HEALTH MART" replace all with HM

Here's what the data looks like when I receive it (before I do the above operations)
Preliminary 202109 TPR.xlsm
BGBH
1Waivers Missed Criteria
78GPR_GUAR,HEALTHMARTGPR
125GPR_GUAR,BPR_GUAR,BPR_GUAR#
136GPR_GUAR,BPR_GUAR,HEALTHMARTBPR
137GPR_GUAR,BPR_GUAR,HEALTHMART#
163BPR_GUARBPR
164GPR_GUAR,BPR_GUAR,HEALTHMARTBPR,GPR
177HEALTHMARTHEALTHMART
254GPR_GUARGPR
269GPR_GUAR,BPR_GUAR,BPR_GUARBPR,GPR
272BPR_GUARBPR
309GPR_GUARGPR
332BPR_GUAR#
345BPR_GUAR#
390BPR_GUAR#
420GPR_GUARGPR
440HEALTHMART,GPR_GUARGPR
451GPR_GUAR,HEALTHMARTGPR
467HEALTHMARTHEALTHMART
490GPR_GUAR,BPR_GUAR,BPR_GUARBPR,GPR,HEALTHMART
494BPR_GUARBPR
576GPR_GUAR,BPR_GUAR,BPR_GUARBPR,GPR
580BPR_GUARBPR
New


After I do the above listed operations, the data looks like the below.
Preliminary 202109 TPR.xlsm
BGBH
1Waivers Missed Criteria
78GPR HMGPR
125GPR BPR BPR#
136GPR BPR HMBPR
137GPR BPR HM#
163BPRBPR
164GPR BPR HMBPR GPR
177 HM HM
254GPRGPR
269GPR BPR BPRBPR GPR
272BPRBPR
309GPRGPR
332BPR#
345BPR#
390BPR#
420GPRGPR
New



At this point, I need to put each cell in alphabetical order and no repeats (not sort the entire column, but the cell, so basically row 269 has GPR BPR BPR and it needs to be BPR GPR), so that ultimately I can add a column with an IF formula that would look at each row and if the two columns match it would say "All Passed")
Here's what final data should look like
Preliminary 202109 TPR.xlsm
BGBH
1Waivers Missed Criteria
78GPR HMGPR
125BPR GPR#
136BPR GPR HMBPR
137GPR BPR HM#
163BPRBPR
164BPR GPR HMBPR GPR
177HMHM
254GPRGPR
269BPR GPRBPR GPR
272BPRBPR
309GPRGPR
332BPR#
345BPR#
390BPR#
420GPRGPR
440GPR HMGPR
451GPR HMGPR
467 HM HM
New


A couple of notes:
The column headers will never change and it will always be column BG and BH
The number of rows does change each month
'#' no action for this, I later just delete this and the cell will be blank
Some months, the Missed Criteria will also have "GCR" which I'd like to put in alphabetical order, so it'd be great if the code allowed for this. Example Missed Criteria column has BPR GPR HM GCR should be BPR GCR GPR HM

Thank you in advance
 

Excel Facts

Save Often
If you start asking yourself if now is a good time to save your Excel workbook, the answer is Yes
Put all of the following code in a module.
Run the macro "replace_on_two_columns"

VBA Code:
Sub replace_on_two_columns()
  Dim a As Variant
  Dim i As Long
  Application.ScreenUpdating = False
  
  With Range("BG2:BH" & Range("BG" & Rows.Count).End(3).Row)
    .Replace "_GUAR", "", xlPart, , False
    .Replace ",", " ", xlPart, , False
    .Replace "HEALTHMART", "HM", xlPart, , False
    .Replace "HEALTH MART", "HM", xlPart, , False
    a = .Value
      ReDim b(1 To UBound(a, 1), 1 To 2)
      For i = 1 To UBound(a)
        b(i, 1) = finaldata(a(i, 1))
        b(i, 2) = finaldata(a(i, 2))
      Next
    .Value = b
  End With
End Sub

Function finaldata(data)
  Dim dic As Object, col As Object
  Dim ky As Variant, itm As Variant
  Dim tmp As String
  
  Set dic = CreateObject("Scripting.Dictionary")
  Set col = CreateObject("System.Collections.ArrayList")

  For Each itm In Split(data, " ")
    dic(itm) = Empty
  Next
  For Each ky In dic.keys
    col.Add ky
  Next
  col.Sort
  For Each ky In col
    If tmp = "" Then tmp = ky Else tmp = tmp & " " & ky
  Next ky
  finaldata = tmp
End Function
 
Upvote 0
This should be way faster:

VBA Code:
Sub SheetReplacements()                                               ' 66940 avg
'
    Dim LastRowInSheet  As Long
    Dim ReplaceArray    As Variant
    Dim WS              As Worksheet
'
    Set WS = Sheets("Sheet1")                                                       ' <--- Set this to the sheet name
'
    LastRowInSheet = WS.Cells.Find("*", , xlFormulas, , xlByRows, xlPrevious).Row   ' Returns a Row Number
'
    With WS.Range("BG2:BH" & LastRowInSheet)
        .Replace What:="HEALTHMART", Replacement:="HM", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
        .Replace What:="HEALTH MART", Replacement:="HM", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
        .Replace What:="_GUAR", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
        .Replace What:=",", Replacement:=" ", LookAt:=xlPart, SearchOrder:=xlByRows, MatchCase:=False
    End With
'
    ReplaceArray = WS.Range("BG2:BH" & LastRowInSheet)                              ' 2 dimensional one based array
'
    For i = 1 To UBound(ReplaceArray)
        If ReplaceArray(i, 1) <> vbNullString Then
            ReplaceArray(i, 1) = RemoveDupeWords((ReplaceArray(i, 1)), " ")
            ReplaceArray(i, 1) = StrSort(ReplaceArray(i, 1))
            ReplaceArray(i, 2) = RemoveDupeWords((ReplaceArray(i, 2)), " ")
            ReplaceArray(i, 2) = StrSort(ReplaceArray(i, 2))
        End If
    Next
'
    WS.Range("BG2:BH" & LastRowInSheet) = ReplaceArray
End Sub


Function RemoveDupeWords(text As String, Optional Delimiter As String = " ") As String
    Dim dictionary As Object
    Dim x, part
 '
    Set dictionary = CreateObject("Scripting.Dictionary")
'
    dictionary.CompareMode = vbTextCompare
'
    For Each x In Split(text, Delimiter)
        part = Trim(x)
'
        If part <> "" And Not dictionary.Exists(part) Then
            dictionary.Add part, Nothing
        End If
    Next
 '
    If dictionary.Count > 0 Then
        RemoveDupeWords = Join(dictionary.keys, Delimiter)
    Else
        RemoveDupeWords = ""
    End If
 '
    Set dictionary = Nothing
End Function


Function StrSort(ByVal sInp As String, Optional bDescending As Boolean = False) As String
'
    Dim asSS() As String                ' substring array
    Dim sSS As String                   ' temp string for exchange
    Dim n As Long
    Dim i As Long
    Dim j As Long
'
'   sorts a space-delimited string
    asSS = Split(sInp, " ")
'
    n = UBound(asSS)
'
    For i = 0 To n
        asSS(i) = Trim(asSS(i))
    Next
'
    If n < 1 Then
        StrSort = sInp
    Else
        For i = 0 To n - 1
            For j = i + 1 To n
                If (asSS(j) < asSS(i)) Xor bDescending Then
                    sSS = asSS(i)
                    asSS(i) = asSS(j)
                    asSS(j) = sSS
                End If
            Next j
        Next i
'
        StrSort = Join(asSS, " ")
    End If
End Function
 
Upvote 0
Here a faster code.
With 10,000 records.
My code from post #2: 20 seconds
Code from post #4: 16 seconds.
My updated code: 4 seconds.

VBA Code:
Sub replace_on_two_columns_2()
  Dim a As Variant
  Dim i As Long
  Application.ScreenUpdating = False
  With ActiveSheet.Range("BG2:BH" & ActiveSheet.Range("BG" & Rows.Count).End(3).Row)
    .Replace "_GUAR", "", xlPart, , False
    .Replace ",", " ", xlPart, , False
    .Replace "HEALTHMART", "HM", xlPart, , False
    .Replace "HEALTH MART", "HM", xlPart, , False
    a = .Value
      ReDim b(1 To UBound(a, 1), 1 To 2)
      For i = 1 To UBound(a)
        b(i, 1) = finaldata_2(a(i, 1))
        b(i, 2) = finaldata_2(a(i, 2))
      Next
    .Value = b
  End With
End Sub

Function finaldata_2(data)
  Dim a As Variant, itm As Variant
  Dim valores As New Collection
  Dim bex As Boolean
  Dim i As Long

  For Each itm In Split(data, " ")
    bex = False
    For i = 1 To valores.Count
      Select Case StrComp(valores(i), itm, vbTextCompare)
        Case 0
          bex = True
          Exit For
        Case 1
          bex = True
          valores.Add itm, itm, Before:=i
          Exit For
      End Select
    Next
    If bex = False Then valores.Add itm, itm
  Next
  ReDim a(1 To valores.Count)
  For i = 1 To valores.Count
    a(i) = valores(i)
  Next
  finaldata_2 = Join(a, " ")
End Function
 
Upvote 0
@DanteAmor, unfortunately I can't stress test your latest submission because it errors out Run time 9, Subscript out of range ... ReDim a(1 To valores.Count)

It appears to run once, but does not want to run multiple times for my my multiple average timing test.

I will try to take another look at it after I get some zzzz.
 
Upvote 0
it errors out Run time 9, Subscript out of range ... ReDim a(1 To valores.Count)

Here the fix when there are empty cells:

VBA Code:
Sub replace_on_two_columns_2()
  Dim a As Variant
  Dim i As Long
  Application.ScreenUpdating = False
  With ActiveSheet.Range("BG2:BH" & ActiveSheet.Range("BG" & Rows.Count).End(3).Row)
    .Replace "_GUAR", "", xlPart, , False
    .Replace ",", " ", xlPart, , False
    .Replace "HEALTHMART", "HM", xlPart, , False
    .Replace "HEALTH MART", "HM", xlPart, , False
    a = .Value
      ReDim b(1 To UBound(a, 1), 1 To 2)
      For i = 1 To UBound(a)
        If a(i, 1) <> "" Then b(i, 1) = finaldata_2(a(i, 1))
        If a(i, 1) <> "" Then b(i, 2) = finaldata_2(a(i, 2))
      Next
    .Value = b
  End With
End Sub

Function finaldata_2(data)
  Dim a As Variant, itm As Variant
  Dim valores As New Collection
  Dim bex As Boolean
  Dim i As Long

  For Each itm In Split(data, " ")
    bex = False
    For i = 1 To valores.Count
      Select Case StrComp(valores(i), itm, vbTextCompare)
        Case 0
          bex = True
          Exit For
        Case 1
          bex = True
          valores.Add itm, itm, Before:=i
          Exit For
      End Select
    Next
    If bex = False Then valores.Add itm, itm
  Next
  ReDim a(1 To valores.Count)
  For i = 1 To valores.Count
    a(i) = valores(i)
  Next
  finaldata_2 = Join(a, " ")
End Function
 
Upvote 0
The most time is consumed by using the Replace function on the sheet. I use the replace function but in memory.
Now the execution is immediate:

VBA Code:
Sub replace_on_two_columns_2()
  Dim a As Variant
  Dim i As Long
  Application.ScreenUpdating = False
  With ActiveSheet.Range("BG2:BH" & ActiveSheet.Range("BG" & Rows.Count).End(3).Row)
    a = .Value
      ReDim b(1 To UBound(a, 1), 1 To 2)
      For i = 1 To UBound(a)
        If a(i, 1) <> "" Then
          b(i, 1) = finaldata_2(replacedata(a(i, 1)))
        End If
        If a(i, 2) <> "" Then
          b(i, 2) = finaldata_2(replacedata(a(i, 2)))
        End If
      Next
    .Value = b
  End With
End Sub

Function replacedata(data)
  data = Replace(Replace(data, "_GUAR", "", , , vbTextCompare), ",", " ")
  data = Replace(data, "HEALTHMART", "HM", , , vbTextCompare)
  replacedata = Replace(data, "HEALTH MART", "HM", , , vbTextCompare)
End Function

Function finaldata_2(data)
  Dim a As Variant, itm As Variant
  Dim valores As New Collection
  Dim bex As Boolean
  Dim i As Long

  For Each itm In Split(data, " ")
    bex = False
    For i = 1 To valores.Count
      Select Case StrComp(valores(i), itm, vbTextCompare)
        Case 0
          bex = True
          Exit For
        Case 1
          bex = True
          valores.Add itm, itm, Before:=i
          Exit For
      End Select
    Next
    If bex = False Then valores.Add itm, itm
  Next
  ReDim a(1 To valores.Count)
  For i = 1 To valores.Count
    a(i) = valores(i)
  Next
  finaldata_2 = Join(a, " ")
End Function
 
Last edited:
Upvote 0
Solution
.55 average seconds with your last code posted for 10k rows. I think that is more than acceptable. (y)
 
Upvote 0

Forum statistics

Threads
1,223,888
Messages
6,175,215
Members
452,618
Latest member
Tam84

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top