MrExcel Message Board


Go Back   MrExcel Message Board > Question Forums > Excel Questions

Excel Questions All Excel/VBA questions - formulas, macros, pivot tables, general help, etc. Please post to this forum in English only.

Reply
 
Thread Tools Display Modes
Old Mar 8th, 2002, 07:44 PM   #1
John McGraw
 
Join Date: Feb 2002
Posts: 76
Default

I would like to know if it is possible to get user written functions to work with array formulas.

As an example, here is a Average function I wrote to illustrate the question:

----
Function MyAverage(DRange As Range) As Double

Dim R As Object
Dim Sum As Double
Dim Count As Integer

Count = 0: Sum = 0

For Each R In DRange
Sum = Sum + R.Value
Count = Count + 1
Next R

MyAverage = Sum / Count

End Function
----

Now, this works fine if I just use it in normal formulas, but it returns "#VALUE!" if I try to use it in an array formula.

So, if column A = {1;1;2;2;1} and
B = {1;4;2;9;10}

I get the following results:

As Array Formulas

{=myaverage(IF(A1:A5=1,B1:B5))} = #VALUE!
{=AVERAGE(IF(A1:A5=1,B1:B5))} = 3

As Normal Formulas

=myaverage(B1:B5) = 5.2
=AVERAGE(B1:B5) = 5.2


How can I a user written function to work in an array formula? Or is it even possible?

Thanks for any help

John
John McGraw is offline   Reply With Quote
Old Mar 8th, 2002, 07:54 PM   #2
Mark W.
MrExcel MVP
 
Join Date: Feb 2002
Location: Austin, Texas USA
Posts: 11,653
Default

Take a look at the data types that you're passing as arguments to MyAverage...

{1;4;FALSE;FALSE;10}

...One of the causes of the #VALUE! error are incompatible data types (see the last entry in the Help Topic for "What does the error #VALUE! mean?"). The AVERAGE worksheet function ignores boolean values -- that's the "trick" behind {=AVERAGE(IF(A1:A5=1,B1:B5))}. How does your UDF handle boolean values? Sorry, I can't answer this question for you. I'm not a VBA guru.

BTW, {=AVERAGE(IF(A1:A5=1,B1:B5))} is 5 instead of 3. Perhaps, you were using a different data set.

[ This Message was edited by: Mark W. on 2002-03-08 15:11 ]
Mark W. is offline   Reply With Quote
Old Mar 9th, 2002, 06:08 PM   #3
Juan Pablo González
MrExcel MVP
 
Join Date: Feb 2002
Location: Bogota, Colombia
Posts: 11,771
Default

Yes, it's possible. The "trick" is that you need to declare your function as a Variant.

Then, handle the info in a temporary array. But, if you need to do an AVERAGEIF function, I would go with Excel's built in way. Or you could just create an UDF that would "appear" as a SUMIF, but, really work as told.
__________________
Regards,

Juan Pablo González
http://www.juanpg.com
Juan Pablo González is offline   Reply With Quote
Old Mar 9th, 2002, 07:18 PM   #4
John McGraw
 
Join Date: Feb 2002
Posts: 76
Default

I tried the variant approach, and it still doesnt work. I simplified the code greatly to JUST focus on getting a function to work with an array formula:
----
Function MyAverage(DRange as Range)As Variant
MyAverage = DRange.Range("A1").Value
End Function
----

In this attempt, I am only trying to assign the function with the value of the 1st cell in the range. It works if I dont enter the function in an array formula, but as an array formula, I still get "#VALUE!"

I'm totally stumped. (I am pressing CTRL-SHIFT-ENTER)
John McGraw is offline   Reply With Quote
Old Mar 9th, 2002, 08:21 PM   #5
Russell Hauf
MrExcel MVP
 
Russell Hauf's Avatar
 
Join Date: Feb 2002
Location: Portland, OR USA
Posts: 1,369
Default

I was able to get it to work using the following code. Hope this helps!


Option Explicit

Function MyAverage(DRange As Variant) As Variant

Dim R As Variant
Dim Sum As Double
Dim Count As Integer
Dim intI As Integer
Dim intJ As Integer

For intI = 1 To UBound(DRange, 1)
For intJ = 1 To UBound(DRange, 2)

If TypeName(DRange(intI, intJ)) <> "Boolean" Then
Sum = Sum + DRange(intI, intJ)
Count = Count + 1
End If

Next intJ
Next intI


MyAverage = Sum / Count

End Function



[ This Message was edited by: Russell Hauf on 2002-03-09 15:23 ]
Russell Hauf is offline   Reply With Quote
Old Mar 9th, 2002, 08:44 PM   #6
Juan Pablo González
MrExcel MVP
 
Join Date: Feb 2002
Location: Bogota, Colombia
Posts: 11,771
Default

Quote:
On 2002-03-09 14:18, John McGraw wrote:
I tried the variant approach, and it still doesnt work. I simplified the code greatly to JUST focus on getting a function to work with an array formula:
----
Function MyAverage(DRange as Range)As Variant
MyAverage = DRange.Range("A1").Value
End Function
----

In this attempt, I am only trying to assign the function with the value of the 1st cell in the range. It works if I dont enter the function in an array formula, but as an array formula, I still get "#VALUE!"

I'm totally stumped. (I am pressing CTRL-SHIFT-ENTER)
This worked for me (With and Without CSE)


Function MyAverage(DRange As Range) As Variant
MyAverage = DRange.Range("A1")
End Function




But, i feel you need this:


Function AverageIf(Range As Range, Criteria As String, Optional Average_Range As Range) As Variant
Dim T As String
If Not Evaluate("OR(" & Left(Criteria, 1) & "={""<"","">"",""=""})") Then _
Criteria = "=" & Criteria
If Average_Range Is Nothing Then
AverageIf = Evaluate("AVERAGE(IF(" & Range.Address & Criteria & "," & Range.Address & "))")
Else
AverageIf = Evaluate("AVERAGE(IF(" & Range.Address & Criteria & "," & Average_Range.Address & "))")
End If
End Function



Which works EXACTLY like SUMIF, no need to array enter.
__________________
Regards,

Juan Pablo González
http://www.juanpg.com
Juan Pablo González is offline   Reply With Quote
Old Mar 9th, 2002, 08:51 PM   #7
John McGraw
 
Join Date: Feb 2002
Posts: 76
Default

Thanks Russell!

I guess I am clueless as to how excel passes the array to the function. You are manipulating it as a 2 dimensional array, but to me it seems like it is 1 dimensional.

In fact, with experimenting with your code I noticed that I could omit the "intj" inner loop and get the same result. (I replaced "DRange(intI,intJ)" with "DRange(IntI,1)") This tells me that the second dimension of the array only includes 1 field. But thats virtually a 1-dimensional array, right?

As Mark W. mentioned, what is being passed to my function is {1;4;FALSE;FALSE;10}, or a 1d array. Why must it be manipulated as a 2d array?

Anyways, your help was great. Thanks again!
John McGraw is offline   Reply With Quote
Old Mar 9th, 2002, 08:59 PM   #8
John McGraw
 
Join Date: Feb 2002
Posts: 76
Default

Quote:
This worked for me (With and Without CSE)


Function MyAverage(DRange As Range) As Variant
MyAverage = DRange.Range("A1")
End Function


It did? I wonder why it didnt work for me?
I changed ".Range("A1").Value" to simply
".Range("A1")" as you have above, and I still get the "#VALUE!" error when entered with CSE.

Thanks for your help anyways!

John
John McGraw is offline   Reply With Quote
Old Mar 10th, 2002, 12:26 AM   #9
Dave Hawley
Banned
 
Join Date: Mar 2002
Posts: 1,582
Default

Hi

You are asking for calculation slow down by using arrays (try Excels Database functions instead) but combining these with UDF's is not advised at all. You see an array formula must loop through all cells referenced and see if the criteria matches (its a bit like uisng a loop in VBA to find a value when the Find Method would get there 100+ times quicker). When you also combine a loop with an array formula it could be doing the same thing twice.

I would strongly advise using the DAVERAGE function for your needs. These functions are at least 100 times faster then array formulas, agian because they are not restricted to having to loop. If however you do use a UDF just add a condition to check, like:

Function MyAverage(DRangeComp As Range, vExclude, dAveRange As Range) As Double
Dim R As Range
Dim vVal
Dim iAveCount As Integer


For Each R In DRangeComp
If R <> vExclude Then
vVal = WorksheetFunction.Sum(dAveRange.Cells(R.Row, 1), vVal)
iAveCount = iAveCount + 1
End If
Next R

MyAverage = vVal / iAveCount
End Function

_________________
Kind Regards
Dave Hawley
OzGrid Business Applications
Microsoft Excel/VBA Training
If it's Excel, then it's us!

[ This Message was edited by: Dave Hawley on 2002-03-09 20:26 ]
Dave Hawley is offline   Reply With Quote
Old Mar 11th, 2002, 01:20 PM   #10
Russell Hauf
MrExcel MVP
 
Russell Hauf's Avatar
 
Join Date: Feb 2002
Location: Portland, OR USA
Posts: 1,369
Default

Quote:
On 2002-03-09 15:51, John McGraw wrote:
Thanks Russell!

I guess I am clueless as to how excel passes the array to the function. You are manipulating it as a 2 dimensional array, but to me it seems like it is 1 dimensional.

In fact, with experimenting with your code I noticed that I could omit the "intj" inner loop and get the same result. (I replaced "DRange(intI,intJ)" with "DRange(IntI,1)") This tells me that the second dimension of the array only includes 1 field. But thats virtually a 1-dimensional array, right?

As Mark W. mentioned, what is being passed to my function is {1;4;FALSE;FALSE;10}, or a 1d array. Why must it be manipulated as a 2d array?

Anyways, your help was great. Thanks again!
You can use it as a one-dimensional array for the range you selected, but in general, ranges you select in Excel are 2-dimensional. So if you select more than one column, you need the second dimension. Also, I suggest modifying the function to include only numeric types in the average (integer, long, single, double) - if you are going to continue along these lines, which you should not (this was just for you to try a UDF array function, correct?).

Regards,

Russell
Russell Hauf is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is On

Forum Jump


All times are GMT +1. The time now is 04:47 AM.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
All contents Copyright 1998-2010 by MrExcel Consulting.
diabetic desserts recipes recipes Diabetic Soups Holiday Pizza Recipes Popcorn Recipes Recipes For Microwave Pasta Recipes Casserole Recipes Chili Recipes Curry Recipes Crockpot Recipes Apples Recipes Bread Recipes Vegetarian Recipes Vegetable recipes Desserts Recipes Appetizers Ethnic Recipes Meat Dishes Barbecue Recipes Sauces Recipes Marinade Recipes Low Fat Recipes Frugal Gourmet Kitchen Classics Recipes On The Grill Cook Books Seafood Recipes Cajun Recipes Breads Low Fat Low Fat Breads Bread Machine Recipes Yeast Breads Quick Breads Fat Free Vegetarian Salad Recipes Eggplant Recipes Radish Recipes Tomato Recipes Jalapeno Recipes Potato Recipes Lettuce Recipes Cabbage Recipes Beans Ambrosia Recipes Biscotti Recipes Desserts Low Fat Cookie Recipes Cheesecake Recipes Cake Recipes Pie Recipes Muffin Recipes Custard Recipes Best Appetizers Appetizers Low Fat Salsa Recipes Dip Recipes International Recipes Afghan Recipes Alaska Recipes French Recipes German Recipes Greek Recipes Italian Recipes Spanish Recipes Thai Recipes Korean Recipes Chinese Recipes Mexican Recipes Indian Recipes Beef Recipes Pork Pork & Ham Pork Butts Pork Chop Recipes Pork Ribs Rulled Pork Poultry Recipes Stews Recipes Ground Beef Barbecue Grill Barbecue Smoker All Purpose Sauce BBQ Sauce Barbecue Sauce Carolina BBQ Sauce Pickle Recipes Marinades Smoking Low Fat Appetizers & Dips Low Fat Breakfast Low Fat Cakes Low Fat Cheesecakes Low Fat Cookies Low Fat Desserts Low Fat Fish & Seafood Low Fat Meats Low Fat Pasta Low Fat Pies Low Fat Salads Low Fat Sandwiches Low Fat Sauces & Condiments Low Fat Sides Low Fat Soups Low Fat Vegetarian Baker's Dozen Taste of Home Recipe Book Bon Appetit Cookbook Blacktie Cookbook Buster Cook Book Cookbook USA Cook Book Cook Book Sara's Cookbook Sara's Cookbook Appetizers and Dips Poultry recipes Diabetic recipes Holiday recipes Miscellaneous recipes 110 recipes 1986 Usenet cookbook 2900 recipes Cyberrealm recipes Great sysops of world Specialty recipes Ceideburg recipes Cheese recipes Chili recipes Fruits recipes Garlic recipes Great chefs of NY Londontowne recipes Raisins recipes Recipes for kids US Food Vegetarian recipes Bread recipes Drinks Meat Dishes Brisket recipes Caribou recipes Chicken recipes Filet mignons recipes Pork recipes Swordfish recipes Turkey recipes Pasta recipes Uncategorized recipes Ethnic recipes Canada recipes English recipes Ethiopia recipes Germany recipes Greece recipes Mexican recipes Philippines recipes Welsh recipes Microwave recipes Soups recipes Vegetable recipes Asparagus recipes Barley recipes Brown rice recipes Lentil recipes Mushrooms recipes Salads recipes Wild rice Desserts recipes Cakes recipes Chocolate recipes Cookies recipes Ice cream recipes