Array formula within VBA

alfordtp

Board Regular
Joined
Oct 3, 2008
Messages
62
I'm trying to VBA code a few calculations. As an Excel array (control-shift-enter) formula, it reads like {=TRIMMEAN(IF(B:B="X",C:C),H2)}, where it is looking at a set of groups (B:B = "X"; find rows that contain "X" in column "B") , then calculating the Trimmean function for column "C" in those rows only. (H2 being the % for Trimmean)

I'm not sure how to do this in VBA.

I'm assuming its some form of WorksheetFunction.TrimMean (Range (If...

This is only one of the array calculations I need to do, so I'm hoping if I can learn how to do this, I can use this example to do the rest of my formulas.

Thanks in advance,

Tim
 

Excel Facts

Can you AutoAverage in Excel?
There is a drop-down next to the AutoSum symbol. Open the drop-down to choose AVERAGE, COUNT, MAX, or MIN
with that intersect, you are not using the whole B&C-columsn, just the used part
The evaluate is just like you write it in a cell, but you have to double the double quote "
Also the ranges are variables here, so there you stop the formula with a double quote and insert the range
VBA Code:
Sub T_Mean()
     With ActiveSheet                                           'your active sheet !!!!
          Set c = Intersect(.UsedRange, .Range("B:B"))          'used part of Bf
          myvalues = Evaluate("=if(" & c.Address & "=""-""," & c.Offset(, 1).Address & ",""x"")")     'an array with the C-value of B-cell is "x"
          MyTrimMean = Application.WorksheetFunction.TrimMean(myvalues, .Range("H2").Value)
     End With
End Sub
 
Upvote 0
@BSALV

thanks for your response. however, I'm not sure if I'm completely following. I've attached an example file of what I'm trying to do.

Let me fully explain my end goal: I'm trying to analyze margins, but exclude the outliers. In order to do that, first I'm calculating the Trimmean. If I understand how Trimmean works, if there are 100 records and you filter out 20%, it will take the top 10 and bottom 10 records out of the calculation. I also want to find the standard deviation of that subset, but (as far as I know) Excel wont do that with a standard formula. So, I'm trying to create a UDF that will calculate the Trimmean and the StdDev of that subset, then identify the records that fall lower than Trimmean - (2 * StdDev).

My attachment shows how I would do it manually, but it takes up quite a bit of resources, so I was hoping a UDF might do it more efficiently.

My end state would look like a set of data on the far left, with part number, group, and margin columns, then on the right (a few columns over), a column of the unique group ids and the Trimmean percentage identified. I would run my UDF in the cells to the right of the margin column.

Excel Example
 
Upvote 0
excel example
you're wrong with the "-" and "x" in your upload #3.
An adjusted macro and 2 UDF's, the one with a dictionary can be used in another sheet then where your data is.
(the other one with evaluate can also be adapted to do the same, but i'm lazy).

In K9:N11 some calculations.
In column E the result of the macro in green and with conditional formatting in blue the one's within the 10%-90% percentile

UDF Example.xlsm
ABCDEFGHIJKLMNO
7xyz
8PartFamilyMarginwith UDF_Evaluate0,5427272730,5888890,54833333
9X1X10%!0,1percentiel 10%0,168with UDF_dictionary0,5427272730,5888890,54833333
10X2X11%!0,11percentiel 90%0,844with macro0,542727273
11X3X50% 0,5with array formula0,5427272730,5888890,54833333
12X4X90% 0,9
13X5X60% 0,6
14X6X55% 0,55
15X7X48% 0,48
16X8X70% 0,7
17X9X65% 0,65
18X10X60% 0,6
19X11X88% 0,88
20X12X50% 0,5
21X13X40% 0,4
22Y1Y60% -
23Y2Y25% -
24Y3Y50% -
25Y4Y20%!-
26Y5Y60% -
Sheet1
Cell Formulas
RangeFormula
L8:N8L8=udf_trimmean1($B$9:$B$38,L$7,$C$9:$C$38,$H$2)
L9:N9L9=udf_trimmean2($B$9:$B$38,L$7,$C$9:$C$38,$H$2)
I9I9=PERCENTILE($E$9:$E$38,0.1)
I10I10=PERCENTILE($E$9:$E$38,0.9)
L11:N11L11=TRIMMEAN(IF($B:$B=L$7,$C:$C),$H$2)
B9:B26B9=LEFT(A9,1)
D9:D26D9=IF(C9<VLOOKUP(B9,$F:$N,9,FALSE),"!","")
Cells with Conditional Formatting
CellConditionCell FormatStop If True
E9:E38Expression=MEDIAAN($I$9:$I$10;$E9)=E9textNO

VBA Code:
Sub tester()

     With ActiveSheet                                           'your active sheet !!!!
          Set c = .Range("B9:B38")                              'the range with the x's
          MsgBox "=if(" & c.Address & "=""x""," & c.Offset(, 1).Address & ",""-"")"     '--->just a msgbox for demo
          myvalues = Evaluate("=if(" & c.Address & "=""x""," & c.Offset(, 1).Address & ",""-"")")     'array that contains the result of this evaluate
          .Range("E9").Resize(UBound(myvalues)).Value = myvalues     'write that array for demo to E9:E38

          MyTrimMean = Application.WorksheetFunction.TrimMean(myvalues, .Range("H2").Value)     'the normal TrimMean-formula
          .Range("L10").Value = MyTrimMean
     End With
End Sub

Function UDF_TrimMean1(Crit_Range As Range, Crit_Value, Val_range As Range, Trim_Perc)
     '**********************************************************************
     'CAUTION : can not be used in another sheet (otherwise i need to add the parent sheetname)
     '**********************************************************************
     'MsgBox "=if(" & Crit_Range.Address & "=" & Crit_Value & "," & Val_range.Address & ",""-"")"     '----> unnecessary, but only to show you the formula within that "evaluate"
     myvalues = Evaluate("=if(" & Crit_Range.Address & "=""" & Crit_Value & """," & Val_range.Address & ",""-"")")
     UDF_TrimMean1 = Application.WorksheetFunction.TrimMean(myvalues, Trim_Perc)
End Function

Function UDF_TrimMean2(Crit_Range As Range, Crit_Value, Val_range As Range, Trim_Perc)
     Set dict = CreateObject("scripting.dictionary")
     c = Crit_Range.Value                                       'read your family to an array
     v = Val_range.Value                                        'read your values to an array
     For i = 1 To UBound(c)                                     'loop through your data
          If StrComp(c(i, 1), Crit_Value, vbTextCompare) = 0 Then dict.Add dict.Count, v(i, 1)     'add the matching values to the dictionary
     Next
     If dict.Count = 0 Then UDF_TrimMean2 = "my error": Exit Function
     UDF_TrimMean2 = Application.WorksheetFunction.TrimMean(dict.items, Trim_Perc)
End Function
 
Upvote 0
Solution
Wow! Thank you so much for putting some time into trying to help me with this problem. I need a little bit to digest. Will let you know if I have any more issues.
 
Upvote 0
this is working. I appreciate all the help with this. I do have a follow-up question:

Like I mentioned before, I'm trying to combine this to also calculate whether values are lower than 2 x StdDev, but the StdDev needs to be of the same range used for the trimmean calculation.

I tried calculating the upper and lower bound limits, then creating an array function combining multiple conditions, trying to mimic my Excel equation:

{=STDEV(IF((B:B=D2)*(C:C>M2)*(C:C<L2),C:C))}

VBA Code:
upbound = Application.WorksheetFunction.Large(myvalues, rectrim)
lowbound = Application.WorksheetFunction.Small(myvalues, rectrim)
   

  
   
stdrange = Evaluate("=if((" & Crit_Range.Address & "=" & Crit_Value & "," & Val_range.Address & ")*(" & myvalues & ">" & lowbound & ")*(" & myvalues & "<" & upbound & ")),-""")
    
    
    
    
UDF_stdev1 = Application.WorksheetFunction.StDev(stdrange)

Can you see if I'm making any obvious mistakes in this? It is not giving me an answer to what the StdDev is of the smaller set of records where all conditions are met.
 
Upvote 0
i can't follow ..., rectrim, what's that ?
you eliminate 10% for example, =5% lower end + 5% upper end and then you check for 2*Stdev for the remaining 90% ?
 
Upvote 0

Forum statistics

Threads
1,223,230
Messages
6,170,883
Members
452,364
Latest member
springate

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