I can't get my first function-formula to work - excel

I am trying to create "my first" formula-function, but can't get it to work.
It returns an error.
First I tested the function as a standard module and rendered the output in the debug console to test the outcome. All worked well.
However I can't get the same module to work as a function
Below the function:
It is called in this way =TEST(val;rng) | resulting in #value!
Function TEST(val As String, rng As Range) As String
Dim a, b As String
Dim cel, itm, tst, s As Range
Dim row, l, i As Integer
'-----------------------------------------------------
a = ""
b = ""
val = "ROX.RFL.avi.Rmd.ice"
Set rng = Range(Sheets("DGR").Cells(3, 3), Cells(3, 34))
'-----------------------------------------------------
For Each cel In rng.Cells
If InStr(UCase(val), UCase(cel)) Then
a = a & UCase(cel) & ","
row = Sheets("DGR").Cells(Rows.Count, cel.Column).End(xlUp).row
If row <> 3 Then
For Each itm In Range(Sheets("DGR").Cells(4, cel.Column), Cells(row, cel.Column))
b = b & UCase(itm) & ","
Next itm
End If
End If
Next cel
'-----------------------------------------------------
For Each tst In Split(a, ",")
If InStr(b, tst) > 0 Then TEST = tst
Next tst
End Function
Below the tested function as a module: (this worked properly)
Sub MKDGR()
Dim val, a, b As String
Dim rng, cel, itm, tst, s As Range
Dim row, l, i As Integer
'-----------------------------------------------------
a = ""
b = ""
val = "ROX.RFL.avi.Rmd.ice"
Set rng = Range(Sheets("DGR").Cells(3, 3), Cells(3, 34))
'-----------------------------------------------------
For Each cel In rng.Cells
If InStr(UCase(val), UCase(cel)) Then
a = a & UCase(cel) & ","
row = Sheets("DGR").Cells(Rows.Count, cel.Column).End(xlUp).row
If row <> 3 Then
For Each itm In Range(Sheets("DGR").Cells(4, cel.Column), Cells(row, cel.Column))
b = b & UCase(itm) & ","
Next itm
End If
End If
Next cel
'-----------------------------------------------------
For Each tst In Split(a, ",")
If InStr(b, tst) > 0 Then Debug.Print tst
Next tst
End Sub

There are lot of things which will or can go wrong. Let's address them one by one
Val is a reservd word in VBA. Avoid using that. Use something which is not a reserved word. For example inptS
Unlike Vb.Net, in VBA when you declare variables you have to explicitly declare each of them. Otherwise they are declared as Variant
When you are dealing with rows in Excel, use Long instead of Integer else you may get an Overflow Error
Use Error handling. This way the code will not break down and gracefully complete the execution and also let you know the problem if any.
Use Line Numbers in your code so that you can use Erl to get the line causing the error. Get MZTools Ver 3. It is free.
Fully qualify your objects. For example, If you don't qualify your range objects then the range object will refer to the Activesheet and the Activesheet may not be the sheet you think it is.
Now let's incorporate all the above in your code.
Code
Option Explicit
Function TEST(inptS As String, rng As Range) As String
Dim a As String, b As String
Dim cel As Range, itm As Range
Dim tst As Variant
Dim row As Long, l As Long, i As Long
'~~> Use error handling
10 On Error GoTo Whoa
'~~> Fully qualify your range objects
20 With Sheets("DGR")
30 For Each cel In rng.Cells
40 If InStr(UCase(inptS), UCase(cel)) Then
50 a = a & UCase(cel) & ","
60 row = .Cells(.Rows.Count, cel.Column).End(xlUp).row
70 If row <> 3 Then
80 For Each itm In .Range(.Cells(4, cel.Column), .Cells(row, cel.Column))
90 b = b & UCase(itm) & ","
100 Next itm
110 End If
120 End If
130 Next cel
140 End With
150 For Each tst In Split(a, ",")
160 If InStr(b, tst) > 0 Then
170 If TEST = "" Then
180 TEST = tst
190 Else
200 TEST = TEST & vbNewLine & tst
210 End If
220 End If
230 Next tst
240 Exit Function
Whoa:
250 TEST = "Unable to calculate value (" & _
Err.Description & _
", Error in line " & Erl & ")"
End Function

Related

Group number sequence inside a range

I am new to VBA and learning myself...
I am facing a similar problem with this post: Excel Vba - Group number sequence inside a string
which the difference is that my item no. is in horizontal like below:
ColA(ID) ColB ColC ColD ColE ColF ColG
A 101 102 103
B 201 202 203 501 502
Sometimes for an ID, there will only have 3 item no., sometimes with 5, they can be upto 30 sometimes...
What I think the function could look like this: Cell G1 = lookupsequence(A1:A30), since that lookup function is no need in this situtation
Then G1 -> 101-103
Then G2 -> 201-203, 501-502
Below is the code I have based on that post, but just generating G1: 101, 102, 103
Lookupsequence(Return_val_col As Range)
Dim i As Long
Dim result As String
Dim initial As String
Dim separator As String
Dim preValue As Integer
Dim value As Integer
preValue = -1
separator = ""
For i = 1 To 30
value = CInt(Return_val_col.Cells(1, i).value)
If value - 1 = preValue Then
result = initial & "-" & value
Else
result = result & separator & value
initial = result
separator = ","
End If
Next
Lookupsequence = Trim(result)
End Function
I tried to add something like but not succeed
Dim lastcol As Long
lastcol = Cells(1, Columns.Count).End(xlToLeft).Column
For i = 1 To lastcol
Thank you
Assuming a max of 30 numbers within the limits of rownumbers of Excel, try:
Function GetSequence(rng1 As Range) As String
Dim rng2 As Range
For Each cl In rng1.SpecialCells(2, 1)
If rng2 Is Nothing Then
Set rng2 = Cells(cl.Value, 1)
Else
Set rng2 = Union(rng2, Cells(cl.Value, 1))
End If
Next
GetSequence = Replace(Replace(rng2.Address(False, False), "A", ""), ":", "-")
End Function
Invoke through: =GetSequence(B1:D1) or whichever range holding the numbers.
If numbers get too large and too many for the above function, try:
Function GetSequence(rng As Range) As String
Dim arr As Variant: arr = rng.Value
With CreateObject("System.Collections.ArrayList")
For Each el In arr
If IsNumeric(el) And el <> "" Then .Add el
Next
.Sort
For i = .Count - 1 To 0 Step -1
If i = .Count - 1 Then
GetSequence = .Item(i) & "|"
Else
If Val(GetSequence) = .Item(i) + 1 Then
If Mid(GetSequence, Len(.Item(i)) + 1, 1) = "-" Then
GetSequence = .Item(i) & Mid(GetSequence, Len(CStr(Val(GetSequence))) + 1)
Else
GetSequence = .Item(i) & "-" & GetSequence
End If
Else
GetSequence = .Item(i) & "," & GetSequence
End If
End If
Next
End With
GetSequence = Replace(GetSequence, "|", "")
End Function
It's abit verbose but this way can even insert empty or unsorted arrays of numbers:
I tested this code and it worked correctly for me. I returned to the page and saw the solution from JvdV; so I thought I'd post my solution too.
Option Explicit
Private Sub Test()
Dim result$
Dim WS As Worksheet
Set WS = ThisWorkbook.Sheets("Sheet3")
result$ = Lookupsequence(WS.Range("B1:AE1"))
result$ = Lookupsequence(WS.Range("B2:AE2"))
result$ = Lookupsequence(WS.Range("B3:AE3"))
End Sub
Private Function Lookupsequence(Return_val_col As Range) As String
Dim preValue%, value%
Dim i&
Dim result$, separator$
preValue = -1
result = ""
separator = ", "
For i = 1 To Return_val_col.count
value = CInt(Return_val_col.Cells(1, i).value)
If value = 0 Then
Exit For
ElseIf result = "" Then
result = value
ElseIf value - 1 <> preValue Then
result = result & "-" & preValue & separator & value
End If
preValue = value
Next
If value = 0 Then
value = preValue
End If
result = result & "-" & value
Lookupsequence = Trim(result)
End Function
My test data in two images from columns A to AE to test the possibility of 30 item numbers

Excel VBA code for finding corresponding pairs of data in two columns

I have a problem with the following code. I have data in columns A and C and want to find matching pairs that are identical in these two columns (column A and C). The pairs should receive an unique identifier in column B and D. This way I can filter out corresponding pairs from column A and C and have two remaining columns that cannot be matched. However, my code keeps looping trough the data when there are duplicates within a column and keeps assigning higher reference numbers.
Sub match()
Dim c As Range, fn As Range, ref As Long
ref = 1
For Each c In Range("A2", Cells(Rows.Count, 1).End(xlUp))
If c <> "" And c <> 0 Then
Set fn = Range("C2", Cells(Rows.Count, 3).End(xlUp)).Find(c.Value, , xlValues, xlWhole)
If Not fn Is Nothing Then
adr = fn.Address
Do
If fn.Offset(, 1) = "" Then
c.Offset(, 1) = ref
fn.Offset(, 1) = ref
ref = ref + 1
Else
Set fn = Range("C2", Cells(Rows.Count, 3).End(xlUp)).FindNext(fn)
End If
Loop While fn.Address <> adr
End If
End If
Next
On Error Resume Next
Range("B2", Cells(Rows.Count, 1).End(xlUp).Offset(, 1)).SpecialCells(xlCellTypeBlanks) = "Not found"
Range("D2", Cells(Rows.Count, 3).End(xlUp).Offset(, 1)).SpecialCells(xlCellTypeBlanks) = "Not Found"
On Error GoTo 0
Err.Clear
End Sub
Does anyone know a solution?
You may benefit from MATCH in array form with Evaluate to fill the column D. The column B is the easy part, just MAX+1
Sub TEST()
Dim i As Long, j As Long
Dim rng_c As Range
Dim rng_b As Range
Dim LR As Long
Dim SR As Long
Dim Myf As WorksheetFunction
Set Myf = Application.WorksheetFunction 'to save some time typing
SR = 1 'starting row of data
LR = Range("A" & Rows.Count).End(xlUp).Row 'last row of data in column A
Set rng_b = Range("B" & SR & ":B" & LR) ' for column B
Set rng_c = Range("C" & SR & ":C" & LR) ' for column C
rng_b.Clear 'must be empty
Range("D" & SR & ":d" & LR).Clear 'must be empty
For i = SR To LR Step 1
If Myf.CountIf(rng_c, Range("A" & i).Value) = 0 Then
Range("B" & i).Value = "Not found"
Else
Range("B" & i).Value = Myf.Max(rng_b) + 1
End If
Next i
j = SR
For i = SR To LR Step 1
If Range("B" & i).Value <> "Not found" Then
j = Evaluate("MATCH(A" & i & ",C" & SR & ":C" & LR & "&D" & SR & ":D" & LR & ",0)")
Range("D" & j).Value = Range("B" & i).Value
End If
Next i
Set rng_b = Nothing
Set rng_c = Nothing
Set Myf = Nothing
End Sub
You could do this without VBA at all, actually.
In D2, write this Formula:
=IF(COUNTIFS($A:$A, $A2, $C:$C, $C2)>1, IF(COUNTIFS($A$1:$A2, $A2, $C$1:$C2, $C2)=1, MAX($D$1:$D1)+1, XLOOKUP($A2 & $C2, $A$1:$A1 & $C$1:$C1, $D$1:$D1)), "Not Found")
Then copy that down column D, and make column B equal to column D
There are several ways of doing this, but you were nearly there!
Here are some slight adjustments:
Sub match()
'''screenupdating false, calc to manual to speed up code
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim c As Range, fn As Range, ref As Long
'setting your ranges for clarity
Dim rng As Range, rng2 As Range
Set rng = Range("A2", Cells(Rows.Count, 1).End(xlUp))
Set rng2 = Range("C2", Cells(Rows.Count, 3).End(xlUp))
'''necessary for rerunning
rng.Offset(0, 1).ClearContents
rng2.Offset(0, 1).ClearContents
ref = 1
For Each c In rng
If c <> "" And c <> 0 Then
'adding After:=rng2.Cells.Count
Set fn = rng2.Find(c.Value, rng2.Cells(rng2.Cells.Count), xlValues, xlWhole)
If Not fn Is Nothing Then
''' placed this back here
adr = fn.Address
Do
'''
'place inside Do ... Loop While
'''adr = fn.Address
'''
If fn.Offset(, 1) = "" Then
c.Offset(, 1) = ref
fn.Offset(, 1) = ref
ref = ref + 1
''' but we do need it here to get out of infinite loop
''' in case
adr = fn.Address
Else
Set fn = rng2.FindNext(fn)
End If
Loop While fn.Address <> adr
End If
End If
Next
On Error Resume Next
Range("B2", Cells(Rows.Count, 1).End(xlUp).Offset(, 1)).SpecialCells(xlCellTypeBlanks) = "Not found"
Range("D2", Cells(Rows.Count, 3).End(xlUp).Offset(, 1)).SpecialCells(xlCellTypeBlanks) = "Not found" '''minor correction: "Not found" (F -> f)
On Error GoTo 0
Err.Clear
'''screenupdating true again, calc to auto
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub
Problem 1: you forget to add the After parameter in .Find(...). See Using the .Find Function VBA - not returning the first value on why you need it.
Problem 2: the statement adr = fn.Address should be inside the Do ... Loop While, else you won't step out of the loop until after the last match; as a result you just kept overwriting the value in c.Offset(, 1) for A8 (leading to 6) and adding values for all its matches in column C (which explains values 4, 5, 6).
Edit: Problem 2 in the strikethrough text above was real, my suggestion on how to fix it quite ignorant. It will cause an infinite loop for a duplicate in rng that does have one or more matches in rng2, but less matches than its own count in rng. E.g. if rng has x 3 times, and rng2 has x twice, the code will loop forever when it gets to the 3rd x and crash Excel. So sorry. Pure luck that the dummy data didn't contain such an example.
Correct solution: keep adr = fn.Address were it was, but add the same statement inside the If fn.Offset(, 1) = "" Then statement. Now, it should work. Code above updated. Triple apostrophes in the code indicate corrections. Added some minor syntax for better performance.
However, as I was testing on a much larger set, I noticed this code was slow. I've found a rather different solution with much better performance, which I will post as a different answer in a sec (in accordance with SO etiquette.
In my other answer I focused on improving your initial code, since you almost got there yourself, and I think one should encourage people's efforts. However, on a larger set, performance wasn't great, so I had a look to see if we could find improvement with a different method. The answer, I think, is "yes". The following solution stores the values from rng2 in an array and on every match alters that match within the array (by adding Chr(1) & ref to the init value). At the end we use another loop to populate rng2.Offset(,1) with the refs through Split()(1) . This way, each new match will simply be the correct match for the new pair, thus avoiding many unnecessary .find commands. Below comparison of 2 tests.
In this snippet "Find_method" refers to code in other answer, "Array_method" refers to answer below.
I'd say, we have ourselves a clear winner. Suggestions for further improvement are of course welcome! Code as follows, with added comments to explain what it does:
Sub matchPairs()
'screenupdating false, calc to manual to speed up code
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim c As Range, fn As Range
Dim ref As Long, c_match As Long, i As Long
Dim rng As Range, rng2 As Range
'set ranges
Set rng = Range("A2", Cells(Rows.Count, 1).End(xlUp))
Set rng2 = Range("C2", Cells(Rows.Count, 3).End(xlUp))
'clear offsets (not strictly necessary for rerun)
rng.Offset(0, 1).ClearContents
rng2.Offset(0, 1).ClearContents
'drop rng2 inside array
Dim DirArray() As Variant
DirArray = Application.Transpose(rng2.Value)
ref = 1 'counter
'looping through init rng
For Each c In rng
'get position match c.Value in DirArray; will throw error if no match
On Error Resume Next
c_match = Application.match(c.Value, DirArray, 0)
'handle error
If Err.Number <> 0 Then
c_match = 0
'reset error handling
Err.Clear
On Error GoTo 0
End If
If c_match = 0 Then
'no match
c.Offset(, 1) = "Not found"
Else
'assign counter
c.Offset(, 1) = ref
'alter match in array, so it won't show up as a match again
'Chr(1) (Start of Header, non-printable ASCII char) won't occur in your data
'we can use it as the delimiter for Split below
DirArray(c_match) = DirArray(c_match) & Chr(1) & ref
'increment counter
ref = ref + 1
End If
Next
'loop over array, and check for presence Chr(1) in each value
For i = LBound(DirArray) To UBound(DirArray)
If InStr(DirArray(i), Chr(1)) = 0 Then
'we didn't alter this entry: it was never found
rng2.Cells(i).Offset(, 1) = "Not found"
Else
'Chr(1) present, get second value from Split array, and put in the offset
rng2.Cells(i).Offset(, 1) = Split(DirArray(i), Chr(1))(1)
End If
Next i
'screenupdating true again, calc to auto
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub

Concatenating data in visible rows within a named range to a string of desired format

I have a data of 10 x 2 dimension. The data looks like below -
year rate
05-06 10%
06-07 20.222%
07-08 13.17%
.
.
.
I want to print this data as a string within a text box present over the chart object and the format of the first column must be a text and the format of the second column must be truncated to one decimal place with a percent symbol. I have concatenated the data as string and pasted it to the text box object over the chart by mapping the cell containing the formula calling the function below.
The string format should look like below -
05-06 : 10.0% ; 06-07 : 20.2% ; 07-08 : 13.2% ...
I have stored this data as a named range rateCurrent and I have used the below code to generate the string of visible rows.
= ConcatenateVisible(rateCurrent, ":", ";")
For time being, assume I have pasted the data starting at column 3, row 8.
Function ConcatenateVisible(rng As Variant, seperator As String, separator1 As String)
For Each cll In rng
If cll.EntireRow.Hidden = False And rng.Column = 3 Then
Debug.Print rng.Row
ConcatenateVisible = ConcatenateVisible & Format(cll.Value, "#") & seperator
Debug.Print cll.Value
Else
Debug.Print rng.Row
ConcatenateVisible = ConcatenateVisible & Format(cll.Value, "0.0%") & seperator1
End If
Next
ConcatenateVisible = Left(ConcatenateVisible, Len(ConcatenateVisible) - Len(seperator))
End Function
For some reason, the second loop is not working and I am receiving the output like below -
05-06 : 10.00000000000 : 06-07 : 20.2222222222 : 07-08 : 13.1765433333 ....
I tried the below function as well which, when added the if loop for format breaks -
Public Function MakeList(ByVal myRange As Range) As String
On Error GoTo Errhand:
Dim c As Range
Dim MyDict As Object: Set MyDict = CreateObject("Scripting.Dictionary")
For i = 1 To myRange.Cells.Count
For Each c In myRange
If Not Rows(c.Row).Hidden Then
If Not MyDict.exists(c.Value2) Then MyDict.Add c.Value2, 1
End If
Next
Debug.Print c, MyDict.keys
If i Mod 2 = 0 Then
MakeList = Join(MyDict.keys, ": ")
Else
MakeList = Join(MyDict.keys, "; ")
End If
Next
cleanExit:
Set MyDict = Nothing
Set c = Nothing
Exit Function
Errhand:
Debug.Print Err.Number, Err.Description
GoTo cleanExit
End Function
Any hints or help or suggestions are much appreciated. TIA.
Try this:
Option Explicit
Function concatenateVisible(rng As Range, Optional separator As String = " : ", _
Optional separator1 As String = " ; ") As String
Dim rw As Range
Dim str As String
str = ""
For Each rw In rng.Rows
If rw.Hidden = False And Len(rw.Cells(1, 1)) > 0 Then
str = str & separator1 & _
rw.Cells(1, 1) & separator & Format(rw.Cells(1, 2), "0.0%")
End If
Next rw
concatenateVisible = Mid(str, Len(separator1))
End Function

Excel VBA - Collection error

I am trying to build a collection and take the Count of Unique Values from that Collection but am getting an error in building a Collection itself. Can anyone suggest me where I am going wrong. Kindly Share your thoughts. Please let me know how to find out the COUNT of UNIQUE VALUES as well.
Sub trial()
Dim sampleVisualBasicColl As Collection
For i = 2 To 10
Rng = Range("M" & i).value
StartsWith = Left(Rng, 3)
If StartsWith = "Joh" Then
sampleVisualBasicColl.Add Rng
Else
End If
Next
Debug.Print (sampleVisualBasicCol1)
End Sub
Using a collection you can just add Joh to the collection and then count the items:
'Using a collection
Sub Col_test()
Dim cCol As Collection
Dim i As Long
Set cCol = New Collection
On Error GoTo Err_Handler
With ThisWorkbook.Worksheets("Sheet1")
For i = 2 To 20
If Left(.Cells(i, 13), 3) = "Joh" Then
cCol.Add .Cells(i, 13).Value, .Cells(i, 13).Value
End If
Next i
End With
Debug.Print cCol.Count
On Error GoTo 0
Exit Sub
Err_Handler:
Select Case Err.Number
Case 457 'This key is already associated with an element of this collection
Err.Clear
Resume Next
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure Col_test."
Err.Clear
End Select
End Sub
If you want the count of each item (Joh, Ben... whatever else you have) then use a dictionary:
'Using a dictionary.
Sub Dic_Test()
Dim dict As Object
Dim i As Long
Dim sValue As String
Dim key As Variant
Set dict = CreateObject("Scripting.Dictionary")
With ThisWorkbook.Worksheets("Sheet1")
For i = 2 To 20
If Len(.Cells(i, 13)) >= 3 Then
sValue = Left(.Cells(i, 13), 3)
If dict.exists(sValue) Then
dict(sValue) = dict(sValue) + 1
Else
dict(sValue) = 1
End If
End If
Next i
End With
For Each key In dict.keys
Debug.Print key & " = " & dict(key)
Next key
End Sub
Note: I'm using Cells within the code rather than Range. Cells(2,13) is M2 (13th column, 2nd row).
I find this link very helpful with dictionaries: https://excelmacromastery.com/vba-dictionary/
As a further update (after answer accepted) and using the lists you gave in your question here: Excel VBA - Formula Counting Unique Value error this code with dictionaries will return Joh = 4, Ian = 3
'Using a dictionary.
Sub Dic_Test()
Dim dict As Object
Dim dictFinal As Object
Dim i As Long
Dim sValue As String
Dim key As Variant
Dim keyFinal As String
Set dict = CreateObject("Scripting.Dictionary")
Set dictFinal = CreateObject("Scripting.Dictionary")
'Get the unique values from the worksheet.
With ThisWorkbook.Worksheets("Sheet1")
For i = 2 To 20
If Len(.Cells(i, 13)) >= 3 Then
sValue = .Cells(i, 13).Value
If dict.exists(sValue) Then
dict(sValue) = dict(sValue) + 1
Else
dict(sValue) = 1
End If
End If
Next i
End With
'Count the unique values in dict.
For Each key In dict.keys
keyFinal = Left(key, 3)
If dictFinal.exists(keyFinal) Then
dictFinal(keyFinal) = dictFinal(keyFinal) + 1
Else
dictFinal(keyFinal) = 1
End If
Next key
For Each key In dictFinal.keys
Debug.Print key & " = " & dictFinal(key)
Next key
End Sub
You need to create the collection as well as declaring it.
Sub trial()
Dim myCol As Collection
Set myCol= New Collection ' creates the collection
For i = 2 To 10
Rng = Range("M" & i).value
StartsWith = Left(Rng, 3)
If StartsWith = "Joh" Then
myCol.Add Rng
Else
End If
Next
For each x in myCol
Debug.Print x
Next x
End Sub
Hey this code will help u since it's collecting Unique values in Listbox,,
Private Sub UserForm_Initialize()
Dim cUnique As Collection
Dim Rng As Range
Dim Cell As Range
Dim sh As Worksheet
Dim vNum As Variant
Set sh = ThisWorkbook.Sheets("Sheet1")
Set Rng = sh.Range("A2", sh.Range("A2").Value ="John". End(xlDown))
Set cUnique = New Collection
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
Me.ListBox1.AddItem vNum
Next vNum
End Sub
You have not declared Variable Rng & i these are the most important thing to do. Meanwhile I would like to suggest this Formula,,
=Sum(if(Frequency (if(Len(B2 :B20) >0,Match(B2 :B20, B2 :B20, 0),""),if(Len(B2 :B20) >Match(B2 :B20, B2 :B20, 0),"",))>0,1))
Its Array formula so finish with Ctrl +shift +enter.
You can use this one also,
Sub CountUnique()Dim i, count, j As Integer count = 1 For i = 1 To 470 flag = False If count
1 Then For j = 1 To count If Sheet1.Cells(i,
3).Value = Sheet1.Cells(j, 11).Value Then flag
= True End If Next j Else flag = False End If If flag = False Then Sheet1.Cells(count,
11 ).Value = Sheet1.Cells(i, 3).Value count = count + 1 End IfNext i Sheet1.Cells( 1 ,
15 ).Value = count End Sub

Having Trouble passing a Cell object? (i could be wrong)

First off thank you very much. Over the last few months (i believe) my coding has progressed drastically. Any and all criticize is always welcome (rip me apart).
Recently I started to try to use different Subs (I dont quite understand when to use functions etc, but i figure it is good structure practice for when i figure it out.
I am hitting a Run-time 424 Error with the following bit of code in Sub ownerCHECK
Sub OccupationNORMALIZATION()
Dim infoBX As String
' initialize variables
LRow = ActiveSheet.UsedRange.Rows.Count
LCol = ActiveSheet.UsedRange.Columns.Count
STATUScounter = LRow
Do While infoBX = ""
infoBX = InputBox("Enter Occupation Column", "Occupation Column")
Loop
restaurCHECK (infoBX)
Application.ScreenUpdating = True
Application.StatusBar = ""
End Sub
-
Sub restaurCHECK(infoBX As String)
Dim RestaurantS(), RestaurantDQs() As Variant
Dim i, LRow, LCol, STATUScounter As Long
Dim rRng As Range
LRow = ActiveSheet.UsedRange.Rows.Count
LCol = ActiveSheet.UsedRange.Columns.Count
STATUScounter = LRow
RestaurantS = Array("estaur", "food", "cafe", "beverage", "waiter", "waitr", _
"waitstaff", "wait staff", "grill") 'array list of target occupations
RestaurantDQs = Array("fast", "pub", "import", "packing", "processing", "packag", _
"retired", "anufact", "distrib") ' disqualifying words for Restaurante category
Set rRng = Range(infoBX & "2:" & infoBX & LRow)
Application.ScreenUpdating = False
For Each cell In rRng
ownerCHECK (cell)
For i = LBound(RestaurantS) To UBound(RestaurantS)
If InStrRev(cell.Value, UCase(RestaurantS(i))) > 0 Then
cell.Offset(, 1) = "Restaurants"
cell.Interior.Color = 52479
End If
Debug.Print cell.Value
Next
For i = LBound(RestaurantDQs) To UBound(RestaurantDQs)
If InStrRev(cell.Value, UCase(RestaurantDQs(i))) And cell.Interior.Color = 52479 Then
cell.Interior.Color = 255
cell.Offset(, 1) = ""
End If
Next
STATUScounter = STATUScounter - 1
Application.StatusBar = "REMAINING ROWS " & STATUScounter & " tristram "
Next cell
End Sub
-
Sub ownerCHECK(str_owner As Range)
Dim owner() As Variant
owner() = Array("owner", "shareholder", "owns ")
For i = LBound(owner) To UBound(owner)
If InStrRev(str_owner, UCase(owner(i))) > 0 Then
cell.Offset(, 2) = "Owner"
End If
Next
End Sub
I can see a couple of issues in ownerCHECK():
"cell" is not defined (unless it's global)
you shouldn't use "cell" as a variable name (internal VBA property)
check validity of incoming range
.
Option Explicit
Sub ownerCHECK(ByRef rngOwner As Range)
If Not rngOwner Is Nothing Then
Dim owner() As Variant
owner() = Array("OWNER", "SHAREHOLDER", "OWNS ")
For i = LBound(owner) To UBound(owner)
If InStrRev(UCase(rngOwner), owner(i)) > 0 Then
rngOwner.Offset(, 2) = "Owner"
End If
Next
End If
End Sub

Resources