I have a large list and want to find all entries for the same project names.
My data looks like this:
A header
Another header
Project names
First
row1
AA_Bla_ABCDEF
Second
Blah
XY_Blah_ABCDEF
Fourth
Again this project name
AA_Bla_ABCDEF
Third
Blubb
12_Blubb_ABCDEF
Therefore, I have this code, which gets all the possible filter criteria (Project names):
lastRow = Range(CStr("C" & ActiveSheet.Rows.Count)).End(xlUp).Row
Dim data(), dict As Object, r As Long
Set dict = CreateObject("Scripting.Dictionary")
data = ActiveSheet.Range("C2", "C" & CStr(lastRow)).Columns(1).Value
For r = 1 To UBound(data)
dict(data(r, 1)) = Empty
Next
data = WorksheetFunction.Transpose(dict.keys())
End Sub
I can access the list of project names like:
Debug.Print data(1, 1) ' AA_Bla_ABCDEF
Debug.Print data(2, 1) ' XY_Blah_ABCDEF
Debug.Print data(3, 1) ' 12_Blubb_ABCDEF
Now, I would like to search in data for all entries that fulfill certain criteria.
I want to exclude all items that do not start with letters. startPattern = "(^[A-Z]{2})"
I want to find in all remaining items those who have the same last 6 symbols (numbers, chars, underscores...) projectPattern = "(.$){6}"
Therefore, I thought of regEx and tried:
Dim regEx As Object
Set regEx = CreateObject("VBScript.RegExp") ' Automatic reference binding
For r = 1 To UBound(data)
With regEx
.Global = True
.MultiLine = True
.IgnoreCase = False
.Pattern = projectPattern
End With
' If data.find(regEx).count > 1 (if I have this pattern more than once)
' similarEntries = data.find(regEx) ...
How can I search the array for all matches that occur more than once?
In the example list it would be only: AA_Bla_ABCDEF
Using LIKE "[A-Z][A-Z]" to exclude some items and RIGHT(string,6) as dictionary key to count duplicates.
Option Explicit
Sub Macro1()
Dim ws As Worksheet
Dim dict As Object, name As String, key, ar
Dim r As Long, lastrow As Long
Set ws = ActiveSheet
Set dict = CreateObject("Scripting.Dictionary")
lastrow = ws.Cells(Rows.Count, "C").End(xlUp).Row
For r = 2 To lastrow
name = Trim(ws.Cells(r, "C"))
If UCase(Left(name, 2)) Like "[A-Z][A-Z]" Then
key = Right(name, 6)
If dict.exists(key) Then
dict(key) = dict(key) & vbTab & name
Else
dict(key) = name
End If
End If
Next
' show results on sheet2
r = 1
For Each key In dict
ar = Split(dict(key), vbTab)
If UBound(ar) > 0 Then
Sheet2.Cells(r, 1) = key
Sheet2.Cells(r, 2) = UBound(ar) + 1
Sheet2.Cells(r, 3).Resize(1, UBound(ar) + 1) = ar
r= r + 1
End If
Next
End Sub
Related
I am trying to assign a identifier to the back of the string if there are duplicate values.
I considered a for loop with a counter but it simply gave me a sequence of numbers in each cells.
Is there another way I can approach this matter?
Sub Macro1()
For i = 1 To 10
For N = 1 To 10
If Worksheets("sheet1").Range("A" & i) = Worksheets("sheet1").Range("A" & N) Then
Worksheets("sheet1").Range("A" & i) = Worksheets("sheet1").Range("A" & i) & counter
counter = counter + 1
End If
Next N
Next i
End Sub
There might be other solutions, but this is what I actually came up with.
Don't forget to add this reference to your project:
Tools -> References -> Microsoft Scripting Runtime -> tick checkbox
Sub Macro1()
' Add reference to project:
' Tools -> References -> Microsoft Scripting Runtime -> tick checkbox
Dim dDict As New Scripting.Dictionary
Dim rngInput As Range
Dim sOutputCol As String
Dim lRow As Long, lCount As Long
With ThisWorkbook.Worksheets("SHEET_NAME") ' SHEET_NAME: the name of the sheet where input is
Set rngInput = .Range("A1:A10") ' A1:A10: the range on the sheet where input is
sOutputCol = "C" ' sOutputCol: output column's letter
For lRow = rngInput.Rows(1).Row To rngInput.Rows(rngInput.Rows.Count).Row
If dDict.Exists(rngInput.Cells(lRow, 1).Value2) Then
lCount = dDict(rngInput.Cells(lRow, 1).Value2)
dDict.Remove rngInput.Cells(lRow, 1).Value2
dDict.Add rngInput.Cells(lRow, 1).Value2, lCount + 1
Else
dDict.Add rngInput.Cells(lRow, 1).Value2, 1
End If
.Cells(lRow, sOutputCol).Value2 = rngInput.Cells(lRow, 1).Value2 & "_" & dDict(rngInput.Cells(lRow, 1).Value2)
Next lRow
End With
End Sub
Here's a slightly different Dictionary approach, which gives you an array of the final values.
Sub Tester()
Dim arr, r As Long, dict As Object, rng As Range, v, tmp
Set dict = CreateObject("scripting.dictionary")
Set rng = ActiveSheet.Range("B1:B20")
arr = rng.Value 'get the input values in an array
For r = 1 To UBound(arr, 1) 'loop over all the values
v = arr(r, 1)
If Not dict.exists(v) Then 'new value?
dict.Add v, Array(r, 1) 'store row for the first occurence and start the count
Else
tmp = dict(v) 'not new value: pull array from dict
tmp(1) = tmp(1) + 1 'increment count for this value
If tmp(1) = 2 Then arr(tmp(0), 1) = arr(tmp(0), 1) & "_1" 'second instance? Flag the first occurence also...
arr(r, 1) = arr(r, 1) & "_" & tmp(1) 'flag the n'th instance
dict(v) = tmp 're-store the array
End If
Next r
rng.Offset(0, 2).Value = arr 'output the (updated) array
End Sub
Hello smart human beings out there
I have this setup in my Excel
Basically, what I'm trying to achieve here is automatically grab every single string from column A (and paste to column H) and return the frequency in column I. The script is below
Sub WordCountTester()
Dim d As Object, k, i As Long, ws As Worksheet
Set ws = ActiveSheet
With ws.ListObjects("Table3")
If Not .DataBodyRange Is Nothing Then
.DataBodyRange.Delete
End If
End With
Set d = WordCounts(ws.Range("A2:A" & ws.Cells(Rows.Count, "A").End(xlUp).Row), _
ws.Range("F2:F" & ws.Cells(Rows.Count, "F").End(xlUp).Row))
'list words and frequencies
For Each k In d.keys
ws.Range("H2").Resize(1, 2).Offset(i, 0).Value = Array(k, d(k))
i = i + 1
Next k
End Sub
'rngTexts = range with text to be word-counted, defined in set d= above
'rngExclude = 'range with words to exclude from count, defined in set d= above
Public Function WordCounts(rngTexts As Range, rngExclude As Range) As Object 'dictionary
Dim words, c As Range, dict As Object, regexp As Object, w, wd As String, m
Set dict = CreateObject("scripting.dictionary")
Set regexp = CreateObject("VBScript.RegExp") 'see link below for reference
With regexp
.Global = True
.MultiLine = True
.ignorecase = True
.Pattern = "[\dA-Z-]{3,}" 'at least 3 characters
End With
'loop over input range
For Each c In rngTexts.Cells
If Len(c.Value) > 0 Then
Set words = regexp.Execute(LCase(c.Value))
'loop over matches
For Each w In words
wd = w.Value 'the text of the match
If Len(wd) > 1 Then 'EDIT: ignore single characters
'increment count if the word is not found in the "excluded" range
If IsError(Application.Match(wd, rngExclude, 0)) Then
dict(wd) = dict(wd) + 1
End If
End If '>1 char
Next w
End If
Next c
Set WordCounts = dict
End Function
However, it currently count the string with 1 word only. I want to count strings with 2 and 3 words (and I will consider drive-by as 2 words). Can someone please tell me where in this code I have to fix to achieve that? I still want to keep column F there because there can be 2- or 3- word strings that I want to exclude. Thanks!
If you changed your mind and consider that also two words pairs 2-3, 4-5, 6-7 and so on are necessary, please test the next solution:
Private Sub WordPairsCountTester()
Dim d As Object, k, i As Long, ws As Worksheet, arrFin
Set ws = ActiveSheet
'Attention, please! The last parameter of the called function means How Many Consecutive Words to be counted
Set d = WordPairCountsSp(ws.Range("A2:A" & ws.cells(rows.count, "A").End(xlUp).row), _
ws.Range("F2:F" & ws.cells(rows.count, "F").End(xlUp).row), 3)
arrFin = Application.Transpose(Array(d.Keys, d.items)) 'place the dictionary in an array
'clear contents of the columns where a previous result was returned, if any...:
ws.Range("H2:I" & ws.Range("H" & ws.rows.count).End(xlUp).row).ClearContents
ws.Range("H2").Resize(UBound(arrFin), 2).Value = arrFin 'drop the array content at once
End Sub
Private Function WordPairCountsSp(rngTexts As Range, rngExclude As Range, nrNeigh As Long) As Object
Dim dict As Object, arr, arrCell, i As Long, pairWd As String, j As Long, k As Long
arr = rngTexts.Value 'place the range in an array for faster iteration
Set dict = CreateObject("scripting.dictionary")
For i = 1 To UBound(arr) 'iterate between the array elements
arrCell = Split(Replace(Replace(Replace(Replace(arr(i, 1), ",", ""), ".", ""), "?", ""), "!", "")) 'split the string by default delimiter (space)
If UBound(arrCell) + 1 >= nrNeigh Then
For j = 0 To UBound(arrCell) - nrNeigh + 1 'iterate between the array elements
pairWd = arrCell(j)
For k = 1 To nrNeigh - 1
pairWd = pairWd & " " & arrCell(j + k) 'create a string from nrNeigh neighbour words
Next k
If IsError(Application.match(pairWd, rngExclude, 0)) Then
dict(pairWd) = dict(pairWd) + 1 'place the unique pairs as keys and add occurrences as items
End If
Next j
End If
Next i
Set WordPairCountsSp = dict 'return the above created dictionary
End Function
I am trying to convert the data based on the max repeated values.
I have truck numbers in col A and "Truck types" in column in B col.
For each unique truck number, the truck type should be same.(This is the expected result)
This can be achieved, by counting the maximum no. of truck types for the unique "truck no", and that cell to be updated with the Max. repeated "Truck type".
If there is equal no. of "Truck types" are available, It should be updated with the first available truck type.
Like this, there are thousands of rows to be updated. This can be
better understand by seeing the attached image.
I have attached the image & expected result is in the column C.
I have googled a lot, but I was unable to find the relevant solution.
Please help.
You do not say anything...
Please, test the next code. It works with assumption that the columns are sorted as we can see in the picture. It is very fast, since the result is put in an array and dropped on the sheet at once:
Sub findMaxCountVehType_Array()
Dim sh As Worksheet, lastRow As Long, rngVeh As Range, rngTemp As Range, arrFin As Variant
Dim i As Long, j As Long, w As Long, count As Long, maxCount As Long, ar As Long, maxStr As String
Set sh = ActiveSheet 'use here your sheet
lastRow = sh.Range("A" & Rows.count).End(xlUp).row
Set rngVeh = sh.Range("A2:C" & lastRow)
ReDim arrFin(1 To lastRow, 1 To 1)
arrFin(1, 1) = "Result": ar = 1
For i = 2 To lastRow
If sh.Range("A" & i).Value = sh.Range("A" & i + 1).Value Then
For j = i To j + 1000 'create a range of type cells for the same vehicle no
If sh.Range("A" & j).Value = sh.Range("A" & i).Value Then
If rngTemp Is Nothing Then
Set rngTemp = sh.Range("B" & j)
Else
Set rngTemp = Union(rngTemp, sh.Range("B" & j))
End If
Else
Exit For
End If
Next j
If rngTemp Is Nothing Then
ar = ar + 1: arrFin(ar, 1) = sh.Range("B" & i)
Else
For w = 1 To rngTemp.Cells.count 'determine the max occurrences string
count = WorksheetFunction.CountIf(rngTemp, rngTemp.Cells(w, 1).Value)
If count > maxCount Then maxCount = count: maxStr = rngTemp.Cells(w, 1).Value
Next
For w = 1 To rngTemp.Cells.count
ar = ar + 1: arrFin(ar, 1) = maxStr 'fill the max count in the array
Next
End If
Set rngTemp = Nothing: maxCount = 0: count = 0 'reinitialize variables
i = i + w - 2 'move the iteration to the following vehicle
Else
ar = ar + 1: arrFin(ar, 1) = sh.Range("B" & i)
End If
Next i
'drop the result array at once
sh.Range("C1").Resize(UBound(arrFin, 1), UBound(arrFin, 2)).Value = arrFin
End Sub
Here is a VBA routine that uses:
A class object which has
key:= Vehicle number
item:= dictionary of associated vehicle types
key:= vehicle type
item:= count of the vehicle types
After collecting the information, we merely need to cycle through the dictionary and extract, for any given vehicle ID, the vehicle type that has the largest count.
This routine, since it works entirely with VBA arrays, should run pretty fast, even with large amounts of data.
Also, with this method, no sorting is required.
ASSUMES the data starts in cell A1 (could be changed if necessary)
ASSUMES results are as you show with Desired Result in column C
Be sure to set a reference (Tools/References) to Microsoft Scripting Runtime
Class Module (rename this module cVehicle)
Option Explicit
Private pVehicleType As String
Private pVehicleTypes As Dictionary
Public Property Get VehicleType() As String
VehicleType = pVehicleType
End Property
Public Property Let VehicleType(Value As String)
pVehicleType = Value
End Property
Public Property Get VehicleTypes() As Dictionary
Set VehicleTypes = pVehicleTypes
End Property
Public Function addVehicleTypesItem(Value)
If pVehicleTypes.Exists(Value) Then
pVehicleTypes(Value) = pVehicleTypes(Value) + 1
Else
pVehicleTypes.Add Key:=Value, Item:=1
End If
End Function
Private Sub Class_Initialize()
Set pVehicleTypes = New Dictionary
pVehicleTypes.CompareMode = TextCompare
End Sub
Regular Module
'Set Reference to Microsoft Scripting Runtime
Option Explicit
Sub vehicle()
Dim dV As Dictionary, cV As cVehicle
Dim wsData As Worksheet, vData As Variant, rRes As Range
Dim V As Variant, I As Long, sKey As String, cKey As String, Cnt As Long
'set data worksheet
'read data into vba array
Set wsData = Worksheets("Sheet3")
With wsData
'add extra column for the "desired results"
vData = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=3)
Set rRes = .Cells(1, 1)
End With
'loop through the data and count the types
'no sorting necessary
Set dV = New Dictionary
For I = 2 To UBound(vData, 1)
Set cV = New cVehicle
With cV
sKey = vData(I, 1)
.VehicleType = vData(I, 2)
If Not dV.Exists(sKey) Then
.addVehicleTypesItem .VehicleType
dV.Add sKey, cV
Else
dV(sKey).addVehicleTypesItem .VehicleType
End If
End With
Next I
'Output the data
I = 1
'Header
vData(I, 3) = "Desired Result"
'Data
For I = 2 To UBound(vData, 1)
sKey = vData(I, 1)
With dV(sKey)
'which type has the highest count
Cnt = 0
For Each V In .VehicleTypes.Keys
If .VehicleTypes(V) > Cnt Then
Cnt = .VehicleTypes(V)
cKey = V
End If
Next V
vData(I, 3) = cKey
End With
Next I
'write the results
Set rRes = rRes.Resize(UBound(vData, 1), UBound(vData, 2))
rRes = vData
End Sub
Is there a way (vba code or excel trick) to manipulate a 2 columnar list so that I get a table with all potential combinations depending on a unique identifier in the first column?
E.g. I have one column with Company Names and another with Country Locations. What I need is every set if combinations of the countries per company (see screenshot attached).
This vba module should solve your problem.
Just copy the code to a new module, declare the input and output columns and the number of the first row of your list.
Note that the code will stop once it hits a line where the "Unique Identifier" Cell is empty.
Also, it requires that your list is sorted with respect to your "Unique Identifier".
If a Unique Identifier only appears once, it will still be written into the output list, but only once and with the outColNation2 staying empty in that row. If this is not desired and it should be left out entirely, just delete the commented if-statement.
Example Image of output
Also note, that a unique identifier can repeat at most 100 times. I assume none of them appears that often as that would create a ridiculously long output list.
Option Compare Text
Sub COMBINATIONS()
Dim i As Long, j As Long, k As Long, l As Long, n As Long
Dim arr(100) As String
Dim UI As String
Dim inColUI As Integer, inColNation As Integer
Dim outColUI As Integer, outColNation1 As Integer, outColNation2 As Integer
Dim FirstRowOfData As Integer
Dim YourWS As Worksheet
inColUI = 1 'Column of the "Unique Identifier"
inColNation = 2 'Column of the "Nations" in your example
outColUI = 4
outColNation1 = 5 'output columns
outColNation2 = 6
FirstRowOfData = 2 'First Row of data
Set YourWS = Application.Worksheets("Sheet1") 'Put in your Worksheet Name here.
i = FirstRowOfData
n = FirstRowOfData
With YourWS
Do Until .Cells(i, inColUI) = ""
j = 0
UI = .Cells(i, inColUI)
Do Until .Cells(i - 1, inColUI) <> .Cells(i, inColUI) And j > 0 Or .Cells(i, inColUI) = ""
arr(j + 1) = .Cells(i, inColNation)
i = i + 1
j = j + 1
Loop
If j = 1 Then '<- remove this if-statement and the following marked lines if single appearing UIs should be omitted entirely
.Cells(n, outColUI) = UI '<---
.Cells(n, outColNation1) = arr(1) '<---
n = n + 1 '<---
Else '<---
For k = 1 To j
For l = 1 To j
If arr(k) <> arr(l) Then
.Cells(n, outColUI) = UI
.Cells(n, outColNation1) = arr(k)
.Cells(n, outColNation2) = arr(l)
n = n + 1
End If
Next l
Next k
End If '<---
Loop
End With
End Sub
Edit: cleaned up the code a little bit
Something like the following shows how to iterate through 2 ranges of cells
Dim Rng1 as Range, Rng2 as Range
Dim SrcCell as Range, OthrCell as Range
Dim FullList as string
Rng1 = Range("A1:A12")
Rng2 = Range("B1:B12")
FullList = ""
For Each SrcCell in Rng1
For Each OthrCell in Rng2
FullList = IIF(FullList="","",FullList & vbCrLf) & SrcCell.Value & OthrCell.Value
Next OthrCell
Next srcCell
The FullList string now contains all the combinations but you may require something else. Only intended to give you a start
You need to add code yourself to filter out duplicates
You can do the following (see code below). As another commentee mentioned, when there is only one record of company vs country, it will not show in the output.
The solutions is based on creating a dictionary, each entry is a company and the value is a comma separated string of countries. After the dictionary is created, the dictionary is looped, and a list of countries is then iterated over a nested loop. If the index of the outer loop is the same as the inner index of the loop then the loop is skipped i.e. that would be a Country 1 vs Country 1 combination. Otherwise is added to the output list.
Columns A,B is input and columns D,E,F is output.
Option Explicit
Public Sub sCombine()
Dim r As Range, dest As Range
Dim d As New Dictionary
Dim key As Variant
Dim countries() As String
Dim i As Integer, j As Integer
On Error GoTo error_next
Set r = Sheet1.Range("A1")
Set dest = Sheet1.Range("D:F")
dest.ClearContents
Set dest = Sheet1.Range("D1")
While r.Value <> ""
If d.Exists(r.Value) Then
d(r.Value) = d(r.Value) & "," & r.Offset(0, 1)
Else
d.Add r.Value, r.Offset(0, 1).Value
End If
Set r = r.Offset(1, 0)
Wend
For Each key In d.Keys
countries = Split(d(key), ",")
For i = LBound(countries) To UBound(countries)
For j = LBound(countries) To UBound(countries)
If i <> j Then
dest.Value = key
dest.Offset(0, 1).Value = countries(i)
dest.Offset(0, 2).Value = countries(j)
Set dest = dest.Offset(1, 0)
End If
Next j
Next i
Next key
Exit Sub
error_next:
MsgBox Err.Description
End Sub
I have two columns "Tag Name" and "keywords" in my input sheet, and the Keywords column has each cell with multiple values separated by comma.
I would like to compare each string value in a cell with other cell values in the Keywords column and if there is a matched instance between the cells return the output in specified format as mentioned below.
My Input will be like below:
Tag Name Keywords
Product1 - Product,System,Features
Product2 - Application,Product,System
Product3 - Application,Apps,System
Expected Output:
Tag Name Keywords
Product1,Product2 - Product
Product1,Product2,Product3 - System
Product2,Product3 - Application
Input and Output Screenshot
Public Function DupeWord(str1 As String, str2 As String) As String
Dim dictStr1Words As New Scripting.Dictionary
Dim colDupeWords As New Collection
'Set up the Regular Expression
Dim oRegExp As New RegExp
Dim oMatches As MatchCollection
Dim oMatch As Match
With oRegExp
.Global = True
.MultiLine = True
.Pattern = "([\w']+)" 'Matches any word character including underscore. Equivalent to '[A-Za-z0-9_']'
Set oMatches = .Execute(str1)
End With
'Add each word in Str1 into a Scripting.Dictionary
For Each oMatch In oMatches
If Not dictStr1Words.Exists(oMatch.Value) Then
dictStr1Words.Add oMatch.Value, 0
End If
Next
Set oMatches = oRegExp.Execute(str2)
'Check to see if any of the words found in Str2 was in Str1 using the Scripting.Dictionary function Exists
For Each oMatch In oMatches
If dictStr1Words.Exists(oMatch.Value) Then
colDupeWords.Add oMatch.Value 'Add any dups to a collection
End If
Next
'If there are any dup words in the collection, join them up as a comma separated list, otherwise return "No Matches!"
If colDupeWords.Count > 0 Then
DupeWord = JoinStringCollection(colDupeWords, ", ")
Else
DupeWord = "No Matches!"
End If
End Function
Public Function JoinStringCollection(colStrings As Collection, strDelimiter As String) As String
'This function joins a collection with a delimiter so that there is no need to lop off a trailing or leading delimiter
Dim strOut As String
Dim i As Long
If colStrings.Count > 0 Then
strOut = colStrings.Item(1)
End If
If colStrings.Count > 1 Then
For i = 2 To colStrings.Count
strOut = strOut & strDelimiter & colStrings.Item(i)
Next
End If
JoinStringCollection = strOut
End Function
In excel sheet i am calling function =Dupeword(A1,A2)
Here is a macro that can reproduce what you want.
I use a dictionary to make a list of the unique keywords.
Each item of that dictionary is another dictionary of the associated tag names
The output is only those primary dictionary items where the secondary dictionary contains more than one item
I use the VBA functions Split and Join to break apart and reform the comma separated lists.
I use early-binding for the dictionary object, finding it easier to code with the advantage of intellisense. But you can easily change it to late-binding, as you have in your code above, if you prefer.
EDIT: Code edited to allow for comma or OR as a delimiter. The Join will always be done with a comma
Option Explicit
Sub TagsForKeywords()
Dim wsSrc As Worksheet, wsRes As Worksheet, rRes As Range
Dim vSrc As Variant, vRes As Variant
Dim dKeyWords As Dictionary, dTagName As Dictionary
Dim I As Long
Dim V As Variant, W As Variant
Dim sKey As String
Dim sDelim As String
Set wsSrc = Worksheets("sheet1")
Set wsRes = Worksheets("sheet1")
Set rRes = wsRes.Cells(1, 7)
With wsSrc
vSrc = .Range(.Cells(1, 1), .Cells(.Rows.Count, 1).End(xlUp)).Resize(columnsize:=2)
End With
Set dKeyWords = New Dictionary
dKeyWords.CompareMode = TextCompare
For I = 2 To UBound(vSrc, 1)
'Find delimiter
sDelim = ","
If InStr(1, vSrc(I, 2), " OR ", vbBinaryCompare) > 0 Then _
sDelim = " OR "
V = Split(vSrc(I, 2), sDelim) 'array of keywords
For Each W In V
sKey = Trim(W)
Set dTagName = New Dictionary
dTagName.CompareMode = TextCompare
If Not dKeyWords.Exists(sKey) Then
dTagName.Add vSrc(I, 1), vSrc(I, 1)
dKeyWords.Add sKey, dTagName
Else
Set dTagName = dKeyWords(sKey)
If Not dTagName.Exists(vSrc(I, 1)) Then _
dTagName.Add vSrc(I, 1), vSrc(I, 1)
Set dKeyWords(sKey) = dTagName
End If
Next W
Next I
'Output results
' Only for Tags that have duplicate keywords
'So Output a row only if there are multiple Products tagged
I = 0
For Each V In dKeyWords.Keys
If dKeyWords(V).Count > 1 Then I = I + 1
Next V
ReDim vRes(0 To I, 1 To 2)
vRes(0, 1) = "Tag Name"
vRes(0, 2) = "Keywords"
I = 0
For Each V In dKeyWords.Keys
If Not dKeyWords(V).Count = 1 Then
I = I + 1
vRes(I, 2) = V
W = dKeyWords(V).Keys
vRes(I, 1) = Join(W, ",")
End If
Next V
Set rRes = rRes.Resize(UBound(vRes, 1) + 1, UBound(vRes, 2))
With rRes
.EntireColumn.Clear
.Value = vRes
.Rows(1).Font.Bold = True
.EntireColumn.AutoFit
End With
End Sub
Multiple delimiters example
you could try this sub
Sub m()
Dim cell As Range
Dim kwd As Variant
With CreateObject("Scripting.Dictionary")
.CompareMode = TextCompare
For Each cell In Range("B2", Cells(Rows.Count, 2).End(xlUp))
For Each kwd In Split(Replace(Replace(cell.Value,"OR",",")," ",""), ",")
.Item(kwd) = .Item(kwd) & cell.Offset(, -1).Value & " "
Next
Next
Range("E1:F1").Value = Range("A1:B1").Value
For Each kwd In .Keys
If UBound(Split(.Item(kwd), " ")) > 1 Then
Cells(Rows.Count, 5).End(xlUp).Offset(1).Resize(, 2).Value = Array(Replace(Trim(.Item(kwd)), " ", ","), kwd)
End If
Next
End With
End Sub