Find text based on common ID - vba

I am trying to find text based on a common phrase. The thing is, the text that I will need to copy out is below the text that I will be searching. For example:
7.  Amazon emailed seller
Friday, February 2, 2018
"Amazon emailed seller" will be consistent, but I need the date that is below it.
Another example:
Claim Amount:
14.97
"Claim Amount:" will be consistent, but I need the amount that is below it.
In the end I am wanting to create a macro (or VBA function if macro is not possible, I apologize for not knowing) that will allow me to search on "Claim Amount:"/"Amazon emailed seller" or another common phrase and will then move the contents of the cell below them to another cell in another workbook. I will not have a cell location for the search to reference because the information I am exporting pastes differently into Excel each time.
Please let me know if you have any questions or if I should clarify anything. I am new to this website and not exactly sure how to phrase my question to be as clear as possible. My apologies in advance.
Thank you!

Here is a fast approach using a
A) datafield array instead of a Range (base data assumed in column A).
B) All found results are written back to a pair of columns that you can change to any other range or a new workbook.
Code
Option Explicit
Sub extract()
' declare and assign variables
Dim header()
header = Array("Amazon emailed seller", "Claim Amount") ' headers
Dim ws As Worksheet ' sheet object (objects have to be SET)
Dim v ' variant datafield array
Dim i As Long, ii As Long, h As Long, n As Long ' counters
Set ws = ThisWorkbook.Worksheets("MySheet") ' << change to your sheet name
n = ws.Range("A" & ws.Rows.Count).End(xlUp).Row ' get last row in column A
' A) create datafield array and loop through items
v = Application.Transpose(ws.Range("A1:B" & n).Value) ' fill 1-based 2-dim datafield array (TWO Columns!)
For i = 1 To n ' loop through array "row"-items
For h = LBound(header) To UBound(header) ' loop through header items
If InStr(v(1, i), header(h)) Then ' check search string against base text
ii = ii + 1 ' increment array counter
v(1, ii) = v(1, i): v(2, ii) = v(1, i + 1) ' enter found values (both rows)
End If
Next h
Next i
ReDim Preserve v(1 To 2, 1 To ii) ' redimension array to actual items count
' -------------------------------------------
' B) Write back results (e.g. in columns D:E) ' << change to ANY wanted pair of columns
' -------------------------------------------
ws.Range("D:E") = "" ' clear columns D:E to get result
ws.Range("D1:E" & ii) = Application.Transpose(v) ' write summary back to columns D:E
' C) Clear memory
Set ws = Nothing
End Sub

This assumes that you know that the text you are looking for will appear somewhere in A1:A20.
=INDEX(A1:A20,MATCH("Claim Amount:",A1:A20,0)+1)
If you do not know which column the text will appear in, you will need to do a match for each possible column OR change your approach (perhaps a helper column).

you could filter all the database in one shot on wanted headers and then get the cells on row below filtered ones
Option Explicit
Sub main()
Dim dataToKeep As Range
Dim headers As Variant
headers = Array("*Amazon emailed seller", "Claim Amount*") 'list your headers (see asterisks for wild characters)
With Worksheets("mySheetName") ' change "mySheetName" to your actual sheet name
With .Range("A1", .Cells(.Rows.Count, 1).End(xlUp)) 'reference its column A cells from row 1 down to last not empty one
.AutoFilter Field:=1, Criteria1:=headers, Operator:=xlFilterValues ' filter reference cells on wnated headers
If Application.WorksheetFunction.Subtotal(103, .Cells) > 0 Then Set dataToKeep = .Offset(1).Resize(.Rows.Count - 1).SpecialCells(xlCellTypeVisible).Offset(1) ' if any filtered cell then get their underlying cells
End With
.AutoFilterMode = False
End With
If Not dataToKeep Is Nothing Then
' code to handle all data underlying the searched "header" cells
End If
End Sub

Related

Macro VBA to Copy Column based on Header and Paste into another Sheet

Background: This is my first time dealing with macros. I will have two worksheets that I’ll be using. The first sheet, ‘Source’ will have data available. The second sheet, ‘Final’ will be blank and is going to be where the macro will be pasting the data I’d like it to collect from the ‘Source’ sheet.
* I want the macro to find the specified header in the ‘Source’ sheet, copy that cell containing the header all the way down to the last row of existing data (instead of the entire column), and paste it onto the ‘Final’ sheet in a specified column (A, B, C, etc.). *
The reason why I have to specify which headers to find is because the headers in the ‘Source’ sheet won’t always be in the same position, but the ‘Final’ sheet’s headers will always be in the same position – so I CAN’T just record macros copying column A in ‘Source’ sheet and pasting in column A in ‘Final’ sheet. Also, one day the ‘Source’ sheet may have 170 rows of data, and another day it may have 180 rows.
Although, it would probably be best to copy the entire column since one of the columns will have a few empty cells rather than to the last row of existing data. I’m assuming it would stop copying when it reaches the first empty cell in the column chosen which would leave out the remaining data after that empty cell in the column – correct me if I’m wrong. If copying the entire column is the best way, then, please provide that as part of the possible solution. I’ve attached an example of the before & after result I would like accomplished:
Example of Result
Find Header=X, copy entire column -> Paste into A1 in ‘Final’ sheet
Find Header=Y, copy entire column -> Paste into B1 in ‘Final’ sheet
Etc..
I’m sorry if my wording isn’t accurate – I tried to explain the best I could. It’d be awesome if someone could help me out on this! Thanks!
u can try with this. i think its clear and step-by-step. it can be very optimized, but to start with vba i think its better this way.
the name of the column must be the same in both sheets.
Sub teste()
Dim val
searchText = "TEXT TO SEARCH"
Sheets("sheet1").Select ' origin sheet
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
x = Selection.Columns.Count ' get number of columns
For i = 1 To x 'iterate trough origin columns
val = Cells(1, i).Value
If val = searchText Then
Cells(1, i).Select
Range(Selection, Selection.End(xlDown)).Select
Selection.Copy
Sheets("sheet2").Select ' destination sheet
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
y = Selection.Columns.Count ' get number of columns
For j = 1 To y 'iterate trough destination columns
If Cells(1, j).Value = searchText Then
Cells(1, j).Select
ActiveSheet.Paste
Exit Sub
End If
Next j
End If
Next i
End Sub
good luck
I modified an answer I gave to another user with similar problem for your case,
I use dictionary function in most of my data sheets so that I can shift columns around without breaking the code, the below code you can shift your columns around and it will still work
the only main restriction is
1. your header names must be unique
2. your header name of interest must be exactly the same.
i.e. your source header of interest is PETER then your Data table should have a header with PETER and it must be unique.
Sub RetrieveData()
Dim wb As Workbook
Dim ws_A As Worksheet
Dim ws_B As Worksheet
Dim HeaderRow_A As Long
Dim HeaderLastColumn_A As Long
Dim TableColStart_A As Long
Dim NameList_A As Object
Dim SourceDataStart As Long
Dim SourceLastRow As Long
Dim Source As Variant
Dim i As Long
Dim ws_B_lastCol As Long
Dim NextEntryline As Long
Dim SourceCol_A As Long
Set wb = ActiveWorkbook
Set ws_A = wb.Worksheets("Sheet A")
Set ws_B = wb.Worksheets("Sheet B")
Set NameList_A = CreateObject("Scripting.Dictionary")
With ws_A
SourceDataStart = 2
HeaderRow_A = 1 'set the header row in sheet A
TableColStart_A = 1 'Set start col in sheet A
HeaderLastColumn_A = .Cells(HeaderRow_A, Columns.Count).End(xlToLeft).Column 'Get number of NAMEs you have
For i = TableColStart_A To HeaderLastColumn_A
If Not NameList_A.Exists(UCase(.Cells(HeaderRow_A, i).Value)) Then 'check if the name exists in the dictionary
NameList_A.Add UCase(.Cells(HeaderRow_A, i).Value), i 'if does not exist record name as KEY and Column number as value in dictionary
End If
Next i
End With
With ws_B 'worksheet you want to paste data into
ws_B_lastCol = .Cells(HeaderRow_A, Columns.Count).End(xlToLeft).Column ' Get number of DATA you have in sheet B
For i = 1 To ws_B_lastCol 'for each data
SourceCol_A = NameList_A(UCase(.Cells(1, i).Value)) 'get the column where the name is in Sheet A from the dictionaary
If SourceCol_A <> 0 Then 'if 0 means the name doesnt exists
SourceLastRow = ws_A.Cells(Rows.Count, SourceCol_A).End(xlUp).Row
Set Source = ws_A.Range(ws_A.Cells(SourceDataStart, SourceCol_A), ws_A.Cells(SourceLastRow, SourceCol_A))
NextEntryline = .Cells(Rows.Count, i).End(xlUp).Row + 1 'get the next entry line of the particular name in sheet A
.Range(.Cells(NextEntryline, i), _
.Cells(NextEntryline, i)) _
.Resize(Source.Rows.Count, Source.Columns.Count).Cells.Value = Source.Cells.Value
End If
Next i
End With
End Sub

Loop with multiple Ranges

Im trying to write a code which determines whether certain cells are empty or not and then returns a set string.
To go in detail; I was hoping for the code to look into cell B2, determine if it is empty, then go to C2 and determine if it is non-empty. If both were correct in cell B2 it would then input "Correct" and move on in the range. However, my code doesnt seem to work because it just inputs "Correct" in every cell in the loop range.
I have posted my code below; any help would be much appreciated.
Sub Fill_Rows()
Dim X As Range
Let Y = Range("C2")
For Each X In Range("B2:B5000")
If X = "" And Y <> "" Then
X = "Correct"
End If
Y = Y + 1
Next X
End Sub
If you meant to check by each row like (B2 and C2) then (B3 and C3), then you could do it like this.
Sub Fill_Rows()
Dim iRow As Long
For iRow = 2 To 5000
If Cells(iRow, "B").Value = vbNullString And Cells(iRow, "C").Value <> vbNullString Then
Cells(iRow, "B").Value = "Correct"
End If
Next iRow
End Sub
Alternative
Added two solutions:
[1] an example code as close as possible to yours and
[2] an alternative using a datafield array to demonstrate a faster way for bigger data sets.
[1] Example Code close to yours
There is no need to use a second variable Y, all the more as apparently you left it undeclared, which always can cause issues (type mismatches, no range object etc.).
So always use Option Explicit in the declaration head of your code module to force yourself to declare all variable types you are using.
Now you can simply use an offset of 1 column to the existing cell to check the neighbouring cell, too.
Option Explicit ' declaration head of your code module (obliges to declare variables)
Sub Fill_RowsViaRangeLoop()
Dim X As Range, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("MySheet") ' << replace with your sheet name
For Each X In ws.Range("B2:B5000")
If X = "" And X.Offset(0, 1) <> "" Then ' column offset 1 checks next cell in C
X = "Correct"
End If
Next X
End Sub
[2] Example Code using a datafield array
Looping through a bigger range isn't very fast, you can speed up your procedure by
assigning your range values to a variant datafield array v, loop through the received array items correcting found items in column 1 and write it back to sheet.
Option Explicit ' declaration head of your code module (obliges to declare variables)
Sub Fill_RowsViaArray()
Dim v As Variant, i As Long, ws As Worksheet
Set ws = ThisWorkbook.Worksheets("MySheet") ' << replace with your sheet name
' Assign values to a 2-dim array
v = ws.Range("B2:C5000") ' or better: v = ws.Range("B2:C5000").Value2
' Check criteria looping over all rows (=first array dimension)
For i = 1 To UBound(v) ' data field arrays are one-based, i.e. they start with 1
If v(i, 1) = vbNullString And v(i, 2) <> vbNullString Then v(i, 1) = "Correct"
Next i
' Write edited array back to original range (adapt the range size to the array boundaries in both dimensions)
ws.Range("B2").Resize(UBound(v, 1), UBound(v, 2)) = v
End Sub
Further Notes
It's good use to fully qualify your sheet or range references (see e.g. object variable ws)
Each array item is identified by a row and a column index.
As such a datafield array is one based (start indices are 1), the first item in row 1 and column 1 will be referred by v(1,1), in col 2 by v(1,2).
In order to count the number of row items you check the upper boundary of its first dimension) via UBound(v,1) or even shorter via Ubound(v)
In order to count the number of columns you check the upper boundary of its second dimension) via UBound(v,2) (here the argument 2 is necessary!)
A comparation using vbNullString can be preferred in coding to "" as it takes less memory (c.f. #PEH 's answer) .

VBA How to loop until the last used cell

I am trying to get the returns of a stock after each close date and list it in a column. My problem is that the start and end dates change and any cell that is not used for returns has to be completely cleared of contents. Here is what I have so far.
Sheets("returns").Range("a2").FormulaR1C1 = _
"=IFERROR(returns(Imported!RC[4],Imported!R[1]C[4]),"""")"
Sheets("returns").Range("a2").Select
Selection.AutoFill Destination:=Range("a2:a937")
Range("a2:a937").Select
Sheets("returns").Range("c2").FormulaR1C1 = _
"=IFERROR(returns(Imported!RC[10],Imported!R[1]C[10]),"""")"
Sheets("returns").Range("C2").Select
Selection.AutoFill Destination:=Range("c2:c937")
Range("C2:C937").Select
This works for what I need but it leaves a formula in the empty cells which I can't have for the next step of my project. It also leaves a -1 return in the last row when I run out of data. The -1 return isn't too big of a deal if that can't be fixed. Is there a way to clear the contents of a cell that doesn't contain a value but contains a formula?
Here’s what I think you want…
You have data in worksheet “Imported”
You want formulas in worksheet “returns” for the same number of rows that exist in worksheet “Imported”
Sub addFormulasBasedOnRecordCount()
' ========================================================
' jdoxey
' Version 1.0
' ========================================================
Dim wsWithData As Worksheet ' the name of the worksheet that has the data
Dim wsFormulas As Worksheet ' the name of the worksheet that you want the formulas in
Set wsWithData = Worksheets("imported") ' change the "name" to be what you want
Set wsFormulas = Worksheets("returns") ' change the "name" to be what you want
Dim activeRows As Long ' this will be the number of rows that have data
' gets the number of rows in "wsWithData",
' assumes that the data starts in "A1"
' and there are no empty rows
activeRows = wsWithData.Range("A1").CurrentRegion.Rows.Count
' puts the formula into column A starting with row 2 though the number of rows in "wsWithData"
wsFormulas.Range("A2:A" & activeRows). _
FormulaR1C1 = "=IFERROR(returns(Imported!RC[4],Imported!R[1]C[4]),"""")"
' puts the formula into column C starting with row 2 though the number of rows in "wsWithData"
wsFormulas.Range("C2:C" & activeRows). _
FormulaR1C1 = "=IFERROR(returns(Imported!RC[10],Imported!R[1]C[10]),"""")"
' ========================================================
' ========================================================
End Sub

Copy cells in excel with vba

I have a code that reads in the new arrangement of columns from a text file and then rearrange the original columns by copying it in at the correct place, however there is a bug in my code. Instead of copying just 1 column it seems to copy all columns to the right of the column that i want to copy..
so i guess the error is here
'copy the old range
ws.Range(ws.Cells(Settings.rowHeader + 1, CounterCol), ws.Cells(lrow, CounterCol)).Copy
I want to copy the range AW3:AW80 to A3:A80, but do i need to copy AW:AW to A:A instead? If i do so the stuff in row 1 will be deleted, below is the full code:
Sub insertColumns()
Call Settings.init
Dim i As Integer
Dim ws As Worksheet
Dim lrow As Integer
Dim columNames As Object
Dim temp As Variant
'fill dictionary with columnnames from text file
Set columNames = FileHandling.getTypes(Settings.columnFile)
Set ws = ActiveWorkbook.Sheets("List")
'Get max column and row number
lColumn = HelpFunctions.getLastColumn(ws, Settings.rowHeader)
lrow = HelpFunctions.getLastRow(ws, HelpFunctions.getColumn("*part*", ws, Settings.rowHeader))
'Insert all new columns in reverse order from dictionary
temp = columNames.keys
For i = columNames.Count - 1 To 0 Step -1
ws.Columns("A:A").Insert Shift:=xlToRight
ws.Range("A" & Settings.rowHeader).Value = temp(i)
Next i
'last column
lastColumn = lColumn + columNames.Count
'we loop through old cells
CounterCol = columNames.Count + 1
Do While CounterCol <= lastColumn
j = 0
'through each elemnt in dictionary
For Each element In temp
j = j + 1
'compare the old rowheader with any of the rowheader in DICTIONARY
If UCase(ws.Cells(Settings.rowHeader, CounterCol).Value) = element Then
'copy the old range
ws.Range(ws.Cells(Settings.rowHeader + 1, CounterCol), ws.Cells(lrow, CounterCol)).Copy
'paste it
ws.Cells(Settings.rowHeader + 1, j).Select
ws.Paste
'format the new row
ws.Cells(Settings.rowHeader + 1, j).EntireColumn.AutoFit
'Delete the old row
ws.Columns(CounterCol).EntireColumn.Delete
'decrease the last column by one since we just deleted the last column
lastColumn = lastColumn - 1
found = True
'Exit For
End If
Next element
'Prompt the user that the old column does not match any of the new column
If Not found Then
MsgBox (UCase(ws.Cells(Settings.rowHeader, CounterCol)) & " was not a valid column name please move manually")
End If
'reset the found
found = False
'go to nect column
CounterCol = CounterCol + 1
Loop
End Sub
Below is a screenshot of the dictionary.
After the first iteration/first copy it should have only copied over the part number column, but as can been seen it has copied over more than just the first column(everything except of drawing number)
Q: I want to copy the range AW3:AW80 to A3:A80, but do i need to copy AW:AW to A:A instead?
A: No. Any range can be copied.
Rather than trying to debug your code, I'll give you a hint about how to debug such a thing. Lines like
ws.Range(ws.Cells(Settings.rowHeader + 1, CounterCol), ws.Cells(lrow, CounterCol)).Copy
are hard to debug because they are trying to do too much. You have 4 instances of the dot operator and suspected that the problem was with the last one (.Copy). The problem is almost certainly that your code isn't grabbing the range that you think it is grabbing. In other words, one or more of your method invocations earlier in the line needs debugging. In such a situation it is useful to introduce some range variables, set them equal to various values and print their addresses to the immediate window to see what is happening. As an added benefit, having set range variables allows you to use the full power of intellisence in the VBA editor. Something like:
Dim SourceRange As Range, Cell1 As Range, Cell2 As Range
'
'
'
Set Cell1 = ws.Cells(Settings.rowHeader + 1, CounterCol)
Set Cell2 = ws.Cells(lrow, CounterCol)
Set SourceRange = ws.Range(Cell1, Cell2)
Debug.Print Cell1.Address & ", " & Cell2.Address & ", " & SourceRange.Address
'
'Once the above is debugged:
'
SourceRange.Copy 'should work as expected
It is possible that you are copying the range that you want to copy but that your larger program still isn't working. In that case you have some sort of logic error and should be trying to copy some other range. Even then, the above exercise still helps because it makes it clear exactly what your original line was doing.
'go to nect column
CounterCol = CounterCol + 1
needed to be deleted. It has to do that the column shifts left when i deleted rows.
Thanks for the help. I hope the code can be used for others who might need to add columns, but still copy over content from old columnsin the right order.

Type Mismatch Error after MsgBox

my data is as below .
Updated Question
Sub Solution()
Dim shData As Worksheet
Set shData = Sheets("Sheet1") 'or other reference to data sheet
Dim coll As Collection, r As Range, j As Long
Dim myArr As Variant
Dim shNew As Worksheet
shData.Activate
'get unique values based on Excel features
Range("a1").AutoFilter
Set coll = New Collection
On Error Resume Next
For Each r In Range("A1:A10")
coll.Add r.Value, r.Value
Next r
On Error GoTo 0
'Debug.Print coll.Count
For j = 1 To coll.Count
MsgBox coll(j)
myArr = coll(j)
Next j
Range("a1").AutoFilter
Dim i As Long
For i = 0 To UBound(myArr)
shData.Range("$A$1").AutoFilter Field:=1, Criteria1:=myArr(i), _
Operator:=xlAnd
On Error Resume Next
Sheets(myArr(i)).Range("A1").CurrentRegion.ClearContents
If Err.Number = 0 Then
Range("A1").CurrentRegion.Copy Sheets(myArr(i)).Range("A1")
Else
Set shNew = Sheets.Add(After:=Sheets(Sheets.Count))
shData.Range("A1").CurrentRegion.Copy shNew.Range("A1")
shNew.Name = myArr(i)
Err.Clear
End If
Next i
'removing filter in master sheet
shData.Range("a1").AutoFilter
End Sub
When I run above macro I don't know why it is giving Type Mismatch Error after MsgBox coll(j) , simply I want to store data in Array and I'm passing that data , Here I am using For Each r In Range("A1:A10") Where A10 length is static how can I find last written column?
When you add something to collection the key needs to be a string so use:
coll.Add r.Value, CStr(r.Value)
instead of:
coll.Add r.Value, r.Value
You are still assigning coll(j) to a Variant which is not an array.
You need to:
ReDim myArr(1 to coll.Count)
Before your for loop and then in the loop:
myArr(j) = coll(j)
Before attempting to respond to this question, I would like to write what I believe you are trying to accomplish; when you confirm this is what you are trying to do, I will try to help you get working code to achieve it. This would normally be done with comments, but the threads of comments so far are a bit disjointed, and the code is quite complex...
You have data in a sheet (called "sheet1" - it might be something else though)
The first column contains certain values that might be repeated
You don't know how many columns there might be... you would like to know that though
You attempt to find each unique value in column A (call it the "key value"), and display it (one at a time) in a message box. This looks more like a debug step than actual functionality for the final program.
You then turn on the autofilter on column A; selecting only rows that match a certain value
Using that same value as the name of a sheet, you see if such a sheet exists: if it does, you clear its contents; if it does not, then you create it at the end of the workbook (and give it the name of the key)
You select all rows with the same (key) value in column A on sheet1, and copy them to the sheet whose name is equal to the value in column A that you filtered on
You want to repeat step 5-8 for each of the unique (key) values in column A
When all is done, I believe you have (at least) one more sheet than you had key values in column A (you also have the initial data sheet); however you do not delete any "superfluous" sheets (with other names). Each sheet will have only rows of data corresponding to the current contents of sheet1 (any earlier data was deleted).
During the operation you turn autofiltering on and off; you want to end up with auto filter disabled.
Please confirm that this is indeed what you are attempting to do. If you could give an idea of the format of the values in column A, that would be helpful. I suspect that some things could be done rather more efficiently than you are currently doing them. Finally I do wonder whether the whole purpose of organizing your data in this way might be to organize the data in a specific way, and maybe do further calculations / graphs etc. There are all kinds of functions built in to excel (VBA) to make the job of data extraction easier - it's rare that this kind of data rearranging is necessary to get a particular job done. If you would care to comment on that...
The following code does all the above. Note the use for For Each, and functions / subroutines to take care of certain tasks (unique, createOrClear, and worksheetExists). This makes the top level code much easier to read and understand. Also note that the error trapping is confined to just a small section where we check if a worksheet exists - for me it ran without problems; if any errors occur, just let me know what was in the worksheet since that might affect what happens (for example, if a cell in column A contains a character not allowed in a sheet name, like /\! etc. Also note that your code was deleting "CurrentRegion". Depending on what you are trying to achieve, "UsedRange" might be better...
Option Explicit
Sub Solution()
Dim shData As Worksheet
Dim nameRange As Range
Dim r As Range, c As Range, A1c As Range, s As String
Dim uniqueNames As Variant, v As Variant
Set shData = Sheets("Sheet1") ' sheet with source data
Set A1c = shData.[A1] ' first cell of data range - referred to a lot...
Set nameRange = Range(A1c, A1c.End(xlDown)) ' find all the contiguous cells in the range
' find the unique values: using custom function
' omit second parameter to suppress dialog
uniqueNames = unique(nameRange, True)
Application.ScreenUpdating = False ' no need for flashing screen...
' check if sheet with each name exists, or create it:
createOrClear uniqueNames
' filter on each value in turn, and copy to corresponding sheet:
For Each v In uniqueNames
A1c.AutoFilter Field:=1, Criteria1:=v, _
Operator:=xlAnd
A1c.CurrentRegion.Copy Sheets(v).[A1]
Next v
' turn auto filter off
A1c.AutoFilter
' and screen updating on
Application.ScreenUpdating = True
End Sub
Function unique(r As Range, Optional show)
' return a variant array containing unique values in range
' optionally present dialog with values found
' inspired by http://stackoverflow.com/questions/3017852/vba-get-unique-values-from-array
Dim d As Object
Dim c As Range
Dim s As String
Dim v As Variant
If IsMissing(show) Then show = False
Set d = CreateObject("Scripting.Dictionary")
' dictionary object will create unique keys
' have to make it case-insensitive
' as sheet names and autofilter are case insensitive
For Each c In r
d(LCase("" & c.Value)) = c.Value
Next c
' the Keys() contain unique values:
unique = d.Keys()
' optionally, show results:
If show Then
' for debug, show the list of unique elements:
s = ""
For Each v In d.Keys
s = s & vbNewLine & v
Next v
MsgBox "unique elements: " & s
End If
End Function
Sub createOrClear(names)
Dim n As Variant
Dim s As String
Dim NewSheet As Worksheet
' loop through list: add new sheets, or delete content
For Each n In names
s = "" & n ' convert to string
If worksheetExists(s) Then
Sheets(s).[A1].CurrentRegion.Clear ' UsedRange might be better...?
Else
With ActiveWorkbook.Sheets
Set NewSheet = .Add(after:=Sheets(.Count))
NewSheet.Name = s
End With
End If
Next n
End Sub
Function worksheetExists(wsName)
' adapted from http://www.mrexcel.com/forum/excel-questions/3228-visual-basic-applications-check-if-worksheet-exists.html
worksheetExists = False
On Error Resume Next
worksheetExists = (Sheets(wsName).Name <> "")
On Error GoTo 0
End Function