Dr. Demento
Well-known Member
- Joined
- Nov 2, 2010
- Messages
- 618
- Office Version
- 2019
- 2016
- Platform
- Windows
I'm attempting to use VBA in place of a nested-If formula (see end of post for original formula that works); I'm comparing two columns and depending on their values, assign a test outcome (four outcomes: true|false + positive|negative). I'm attempting to use CASE instead of IF, but I'm running into issues because some of my conditions use NOT. Additionally, I'm testing strings in an array, so trying to use a function to test the absence of a string value isn't working too well either.
I'd rather not use a UDF, as the file is already really large, but instead want to evaluate the the conditions and simply write the value to a column. I'm also looking to avoid loops, as I'm trying to learn efficient coding. I'm not married to using CASE, but I thought it would be more efficient than IF.
As an aside - what's the syntax for NOT X NOR Y - is it:
NOT(OR(X, Y)) or
OR(NOT(X), NOT(Y))
Thanks much, everyone.
Here is the original, working formula:
Note: J2 = arrTest || N2 = arrGold
=IF(AND(OR($J2="SP"|$J2="S")|$N2="S")|"TP"|
IF(AND(OR($J2="SP"|$J2="S")|OR($N2="A"|$N2="H"|$N2="N"|$N2="U"))|"FP"|
IF(AND(NOT(OR($J2="SP"|$J2="S"))|$N2="S")|"FN"|
IF(AND(NOT(OR($J2="SP"|$J2="S"))|NOT(OR($N2="S")))|"TN"))))
I'd rather not use a UDF, as the file is already really large, but instead want to evaluate the the conditions and simply write the value to a column. I'm also looking to avoid loops, as I'm trying to learn efficient coding. I'm not married to using CASE, but I thought it would be more efficient than IF.
As an aside - what's the syntax for NOT X NOR Y - is it:
NOT(OR(X, Y)) or
OR(NOT(X), NOT(Y))
Thanks much, everyone.
Code:
Option Explicit
Sub AssignSensSpec()
Dim sht As Worksheet
Dim arrTest As Variant
Dim arrGold As Variant
Dim arrSn_Sp As Variant
Dim strTest As String
Dim cntr As Integer
Dim lrow As Integer
Set sht = ThisWorkbook.Sheets("Data")
Set arrTest = sht.Range("J2:J6950")
Set arrGold = sht.Range("N2:N6950")
' ~~ resize final array
With sht
.Activate
lrow = .Cells(Rows.Count, 1).End(xlUp).Row
If lrow = 2 Then
Application.ScreenUpdating = True
MsgBox ("Sheet Data does not contain any raw data - macro terminated!")
Exit Sub
End If
arrSn_Sp = sht.Range("A2").CurrentRegion.Resize(, 1)
End With
For cntr = 1 To lrow
Select Case arrSn_Sp(cntr, 1)
Case IsInArray(arrGold, Not ("S")) = True
Case (IsInArray(arrTest(cntr), Not ("SP")) = True) Or (IsInArray(arrTest(cntr), Not ("S")) = True)
arrSn_Sp(cntr) = "TN"
Case (IsInArray(arrTest(cntr), ("SP")) = True) Or (IsInArray(arrTest(cntr), ("S")) = True)
arrSn_Sp(cntr) = "FP"
Case IsInArray(arrGold(cntr), "S")
Case IsInArray(arrTest(cntr), "S") Or IsInArray(arrTest(cntr), "SP")
arrSn_Sp(cntr) = "TP"
Case IsInArray(arrTest(cntr), Not ("SP")) Or IsInArray(arrTest(cntr), Not ("S"))
arrSn_Sp(cntr) = "FN"
End Select
Next cntr
sht.Range("AK2:AK6950") = arrSn_Sp
End Sub
Function IsInArray(arr As Variant, valueToFind As Variant) As Boolean
' checks if valueToFind is found in array, no loop!
' http://www.jpsoftwaretech.com/finding-values-in-an-array-without-looping/
IsInArray = (UBound(Filter(arr, valueToFind)) > -1)
End Function
Here is the original, working formula:
Note: J2 = arrTest || N2 = arrGold
=IF(AND(OR($J2="SP"|$J2="S")|$N2="S")|"TP"|
IF(AND(OR($J2="SP"|$J2="S")|OR($N2="A"|$N2="H"|$N2="N"|$N2="U"))|"FP"|
IF(AND(NOT(OR($J2="SP"|$J2="S"))|$N2="S")|"FN"|
IF(AND(NOT(OR($J2="SP"|$J2="S"))|NOT(OR($N2="S")))|"TN"))))