Create VBA Function using existing Excel Functions

dmikhailov4

New Member
Joined
Jul 23, 2018
Messages
10
Reference

Result of Formula

Dog
1
Dog
1
Cat
2
Cat
2
Cat
2
Horse
1
Sheep
2
Sheep
2

<tbody>
</tbody>

Hi,



I’m hoping someone can help me with writing a VBA code to create a function that converts a formula I use to an easier function, using existing Excel Functions (namely, INDIRECT, ADDRESS, ROW, COLUMN):

Regular Formula
=IF(A2=INDIRECT(ADDRESS(ROW(A2)-1,COLUMN(A2))),INDIRECT(ADDRESS(ROW()-1,COLUMN())),IF(INDIRECT(ADDRESS(ROW()-1,COLUMN()))=1,2,1))

…into this
=GROUPBANDING(Ref,Val1,Val2)…where in the above formula Ref=A2, Val1=1, Val2=2.

Description of whatthe formula is doing:
As per the table above, IF the Ref cell equals the row above it, the Result equals the Result above that (in the 2nd column). Ifnot, it equals an alternative value. In this case, the numbers alternatebetween 1 and 2 (later, I use this to conditionally format all the 2s to befilled with another color – it’s like colored banding, but instead ofalternating between every row, it alternates between every group of referencecells - I can't get colors to work in the example table above, though).


My current VBA Code:
-------------------------------------------------------

Function GROUPBANDING(Ref, Val1, Val2)

If Range(Ref) =INDIRECT(ADDRESS(ROW(Ref) - 1, COLUMN(Ref))) Then
INDIRECT(ADDRESS(ROW() - 1, COLUMN()))
ElseIf INDIRECT(ADDRESS(ROW() - 1, COLUMN())) = Val1 Then
Val2
Else
Val1
End If

End Function
-------------------------------------------------------

Error message I get:
“Compile Error: Sub or Function not defined” and points to the first instance of “ROW”

I’ve not needed to make Functions in the past so I’m not as adept at these, so any help or guidance would be appreciated! Thanks!
 

Excel Facts

Did you know Excel offers Filter by Selection?
Add the AutoFilter icon to the Quick Access Toolbar. Select a cell containing Apple, click AutoFilter, and you will get all rows with Apple
Something like this should do it:
Code:
Function newnu(Ref As Range, Var1, Var2)

Refv = Ref.Value
Up1 = Ref.Offset(-1, 0).Value
If Up1 = Refv Then
newnu = Var1
Else
newnu = Var2


End If
 
Upvote 0
Welcome to the forum.

First of all, that formula is not written well. It's not usually required to use INDIRECT and ADDRESS because Excel automatically updates the references when you copy/paste or drag a formula. Your formula can be rewritten as:

=IF(A2=A1,B1,IF(B1=1,2,1))

Second, VBA is generally far different from spreadsheet formulas. You can use EVALUATE to evaluate a string as a formula, but there's usually a better way using native VBA. Your code is giving errors since it is not standard VBA language.

So try the formula first and see how that works for you. We could write something in VBA, but the native formula I provided will be much quicker and should be easy enough for you to see.
 
Upvote 0
Incidentally, you can get the group banding effect using just Conditional formatting. Assuming "Reference" is in A1, select A2:A1000 (whatever your bottom row is), click Conditional Formatting > New Rule > Use a formula and enter:

=AND(A2<>"",MOD(SUMPRODUCT(--(A$1:A1<>A$2:A2)),2))

click Format and choose a fill color.
 
Upvote 0
Eric W,

I appreciate the reply, but the use of Indirect was intentional because if you delete a row, for example, you get a reference error, so this is a fool-proof fail-safe for that. Your formula is what I used in the past, until I got that problem.

I will play with the Evaluate recommendation tho, but I think you're right about native VBA which is what I'm seeking.

Thanks Again,
Daniel
 
Upvote 0
Incidentally, you can get the group banding effect using just Conditional formatting. Assuming "Reference" is in A1, select A2:A1000 (whatever your bottom row is), click Conditional Formatting > New Rule > Use a formula and enter:

=AND(A2<>"",MOD(SUMPRODUCT(--(A$1:A1<>A$2:A2)),2))

click Format and choose a fill color.

Eric W,

Thanks also for this, but it's not working as intended. Basically myconditional format reads as "=$B1=2" then fill light blue. You'reright that my original formula could be put directly into the conditionalformatting formula, but conditional formatting is VERY finicky, if you dosomething like insert rows or even something as simple as copying one cell intoanother, so merging the two would be much harder to maintain.


I did try yourformula though, and it didn’t seem to work I’m afraid – not sure why, but Iwonder if the formula you have above is an array formula (never used arrays inconditional formatting).

Thanks againanyhow!
Daniel
 
Upvote 0
Something like this should do it:
Code:
Function newnu(Ref As Range, Var1, Var2)

Refv = Ref.Value
Up1 = Ref.Offset(-1, 0).Value
If Up1 = Refv Then
newnu = Var1
Else
newnu = Var2


End If

OffTheLip,



Thanks so muchfor taking a stab at this. The OFFSET is a great idea. This is definitely inthe right direction, but where you have “Up1” Defined to return the value of the cell above the the Reference (in the example it would be A1), I instead what it to be Up1 of the cell containing the actualformula (i.e., B1 in the example).



Likewise, thereis another If statement nested here such that if the Reference and the oneabove are not equal, and if the cell above the formula cell is Var1,then it should be Var2; if Var2, it should be Var1.



So to modifyyour code it would read:

Function newnu(RefAs Range, Var1, Var2)



Refv = Ref.Value

Up1 =Ref.Offset(-1, 0).Value



If Up1 = RefvThen

newnu = <s>Up1</s>Up2

‘ newnu should equal the cell directly above where the formula is (incolumn B), but Up1 would point to the cell above the Reference (in column A). Howdo I point to the cell above the formula?



ElseIf Up2= Val1 Then

newnu = Val2

Else

newnu = Val1



End If


End Function

 
Upvote 0
Well, if you are concerned with deleting or adding rows, try this formula:

=IF(A2=OFFSET(A2,-1,),OFFSET(B2,-1,),IF(OFFSET(B2,-1,)=1,2,1))

in B2. There are only references in the current row, so it should work fine. If you really want a UDF, then try:
Code:
Public Function GroupBanding(ByVal Cell1 As Range, ByVal Cell2 As Range) As Long

    If Cell1 = Cell1.Offset(-1) Then
        GroupBanding = Cell2.Offset(-1)
    Else
        GroupBanding = IIf(Cell2.Offset(-1) = 1, 2, 1)
    End If
        
End Function
where the formula in B2 would be:

=GroupBanding(A2,B2)

Finally, the CF formula I showed you does work for me, but like you said CF can be finicky, especially when you add/delete ranges. The formula I showed was not (technically) an array formula. However, as it happens CF can handle array formulas.

Hope this helps.
 
Upvote 0
Here is another option that should be fine with row deletions.
Leave B1 empty

BTW, what are you doing about row insertions?

Excel Workbook
AB
1Reference
2Dog1
3Dog1
4Cat0
5Cat0
6Cat0
7Horse1
8Sheep0
9Sheep0
Numbers for banding
 
Last edited:
Upvote 0

Forum statistics

Threads
1,217,202
Messages
6,135,166
Members
449,914
Latest member
JSW

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