Here’s part of a spreadsheet for a golf league.

The formula in AA is just an AVERAGE(), but the one in AB is a little more interesting. It looks like this:

`{=IF(COUNT(B2:Z2)<5,AA2,(SUM((Z2:INDEX(A2:Z2,LARGE(COLUMN(A2:Z2)*(A2:Z2<>""),5))))-LARGE((Z2:INDEX(A2:Z2,LARGE(COLUMN(A2:Z2)*(A2:Z2<>""),5))),1))/4)}`

This formula takes the last five scores, throws out the highest one, and averages the remaining four scores. If the player has less than five scores, it’s just a simple average. I did some similar calculations in Golf Handicap and Sum Last Three Golf Scores if you’re interested. Let’s break this one down.

**Array Formula**

First, this formula is an array formula. When you enter it correctly, using Ctrl+Shift+Enter rather than just Enter, Excel puts the curly braces around the formula. If you don’t enter it correctly, Excel will still usually return a result, just not the right result. So please enter it correctly. Stuff like this is why Enron doesn’t have a golf league anymore.

Some formulas act on numbers. `1+2 = 3`

takes two numbers and adds them together. Array formulas act on arrays of numbers. `{1,10,100}+{2,20,200} = {3,30,300}`

. As you can see, when the arrays are added, each element of the array is added to its brother and the result isn’t a number, it’s an array of numbers. If you want to see a cleaner example of an array formula and how they work, go read Anatomy of an Array Formula.

**The IF Part**

`{=IF(COUNT(B2:Z2)<5,AA2,*Some Array Stuff*)}`

The IF part is pretty straight forward. The COUNT function returns how many numbers are in the range to see if there are enough scores. If there are, do the array magic. If there aren't, get the average that we've computed in AA2.

**The SUM Part**

`(SUM(*Stuff that returns an array*)-LARGE(*Stuff that returns an array*,1)/4`

Remember when I said that adding arrays returns an array. The same is true for multiplication. The purpose of an array formula is to return an array *into* a function that does something with an array. We don't want to get an array back from our formula, we want to get an array to plug into the SUM function so that we can add it up and get one number back.

In this part of the formula, we're summing up the array, subtracting out the 1st largest value (`LARGE(x,1)`

returns the largest value in x, while `LARGE(x,3)`

returns the third largest value.), and finally dividing the whole mess by 4 to get an average.

**The INDEX Part**

`Z2:INDEX(A2:Z2,*Some array stuff that returns a column number*)`

Cell references that span more than one cell look like B2:Z2, with a colon separating the first cell in the range with the last cell in the range. What you may not know is that Excel doesn't really care which order they're in. To Excel, Z2:B2 is the same as B2:Z2. Go try it. Go type `=SUM(Z2:B2)`

in a worksheet and see what happens.

In this part of the formula, we're starting with Z2, then a colon. The INDEX function is going to return a cell reference that makes up the second part of our multi-cell range. For instance, on line 3 in the above screen shot, the INDEX function is going to return K3, so that when Excel evaluates the formula in AB3, it will reduce this part to Z3:K3 and then convert that to K3:Z3. K3:Z3 happens to be the range that covers Andrew's last five scores.

With INDEX, you supply a range and a number that says which cell in that range you want. In our example, we're supplying the range A3:Z3 (the entirety of the scores) and we're doing some calculations that return which cell in A3:Z3 we want to be the Z3's partner.

**The LARGE Part**

`LARGE(*the array stuff*,5)`

In The SUM part, we talked about how LARGE works because we were trying to find the largest number in an array to get rid of. Here we're using LARGE in a different part of the formula. We're finding the 5th largest value in some array. Why fifth? Because we want five golf scores. This is the part that, in line 3, helps us find K3 so we can sum up K3:Z3.

The array that we're getting the 5th largest value from is an array of column numbers that have non-blank cells. Of all the cells on line 3 between A and Z, K3 is the fifth largest column number (K=11 if column letters were actually numbers) if you only consider cells that aren't blanks. N3 would be the fourth largest and P3 the second largest, to name a few.

**The Array Part**

`COLUMN(A2:Z2)*(A2:Z2<>"")`

Finally the good part. This is the part where we multiply two arrays together and the part that makes this formula an array formula rather than the normal kind. We've kind of worked from the outside in on this formula, but I'm going to walk back from the inside out so we don't lose perspective on this part.

The array part returns an array of column numbers. That goes into the LARGE function so we can find the fifth largest column number that has a value. That cell gets married to Z3 to make a multi-cell range. The range gets put into a SUM function that adds up the five scores in the range.

You may notice that the array part is repeated in the formula. It's in the SUM part so we can get to the five values. It's also in the LARGE part so we can pick out the largest of those five values to discard.

I mentioned earlier that we can multiply arrays and get an array in return. We're multiplying two arrays that each have 26 elements (A-Z is 26).

`COLUMN(A3:Z3)*(A3:Z3<>"")`

As arrays, the above looks like this:

`{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}*{TRUE,TRUE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,FALSE,FALSE,TRUE,TRUE,TRUE,TRUE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE}`

The COLUMN function returns the column number for the range, 1 to 26 in this case. The second array is created by comparing each cell in A3:Z3 to an empty string, thereby testing whether the cell is empty. If it's not equal to an empty string, that element of the array gets a TRUE. If it is empty, it gets a FALSE. We end up with 26 TRUEs and FALSEs telling us which columns have values.

Now here's the magic. When you do math on a TRUE or FALSE, it converts into a number; TRUE becomes 1 and FALSE becomes 0. When we multiply each element of the arrays to each other, remembering how TRUEs and FALSEs are treated, we get

`{1,2,3,4,5,6,0,0,9,10,11,0,0,14,15,16,17,0,0,0,0,0,0,0,0,0}`

Every column that had a value gets the column number. Every column that had no value gets a zero. We have a 26 element array with column numbers and zeros. This array gets jammed into a LARGE function that returns the fifth largest value. What's the fifth largest value in this array? It's 11.

The 11 gets jammed into and INDEX function to return the 11th cell of A3:Z3, which is K3.

K3 gets tacked onto Z3 to make Z3:K3 and that gets converted to K3:Z3.

K3:Z3 gets jammed into a SUM function and returns 40, the sum of the last five scores. Elsewhere, K3:Z3 gets jammed into a LARGE(x,1) function to return the largest value in K3:Z3, or 14.

We take the sum, 40, subtract the large, 14, and get 26. Divide 26 by 4 and we get 6.5, the number in AB3.

And that's it. Now you know about array formulas, INDEX, LARGE, COUNT, and COLUMN. I assume you already knew about IF and SUM. Do you get how it works? OK smart guy. What do you need to change to get the best 4 out of 6?

years ago i had to do a low 3 of 5 average for my brother’s golf league. this is what i used.

=IF(ISBLANK(E9),””,AVERAGE(SMALL(IF(OFFSET(B9:T9,0,MATCH(1E+300,B9:T9)-5,1,5)=0,MAX(B9:T9),OFFSET(B9:T9,0,MATCH(1E+300,B9:T9)-5,1,5)),{1,2,3})))

You can adapt this to calculate players’ handicaps (lowest 10 of last 20)

In googledocs, formula is (no check for minimum # of scores):

=ArrayFormula(sum(small(offset(J20,-19,-2,20,1),row($1:$10))))/10*.96

or ?

{=SUM((COLUMN(B2:Z2)=LARGE((B2:Z2>0)*(COLUMN(B2:Z2));ROW($2:$5)))*(B2:Z2))/4}

snb: I don’t get the same answers with that. I doesn’t seem to account for which of last five is the largest and should be thrown out.

If large(x,1) is the largest, then large(x,2:5) should only take the second largest to the 5th largest into account, don’t you think ?

Yes, but the formula takes the 2nd to 5th largest column numbers, no values. It needs to be the 2nd to 5th largest values of the 1st to 5th largest column numbers. At least I think that’s why it gave different results.

This looks useful for all sorts of things, as well as golf scores, but I’m not keen on ultra-long spreadsheet formulas, so I wrote a UDF to do the same thing at http://newtonexcelbach.wordpress.com/2013/07/30/selectav-function/.

You can select how many values to average, and how many of the highest (and/or lowest) values to exclude from the average.

@Dick

You are quite right; it should be:

{=IF(COUNT(B2:Z2)0)*(COLUMN(B2:Z2));ROW($1:$5)))*(B2:Z2);ROW($2:$5))/4))}

Wrong formula pasted: (pleas remove last post)

{=IF(COUNT(B3:Z3)0)*(COLUMN(B3:Z3));ROW($1:$5)))*(B3:Z3);ROW($2:$5))/4))}

Somethin strnag ein the neighbourhood

=IF(COUNT(B3:Z3)0)*(COLUMN(B3:Z3)),ROW($1:$5)))*(B3:Z3),ROW($2:$5))/4))

It seems to be impossible to upload this formula, without being distorted.

`=IF(COUNT(B3:Z3)<5,AVERAGE(B3:Z3),SUM(LARGE((COLUMN(B3:Z3)=LARGE((B3:Z3>0)*(COLUMN(B3:Z3)),ROW($1:$5)))*(B3:Z3),ROW($2:$5))/4))`

or

`{=AVERAGE(IF(COUNT(B2:Z2)<5;B2:Z2;LARGE((COLUMN(B2:Z2)=LARGE((B2:Z2>0)*(COLUMN(B2:Z2));ROW($1:$5)))*(B2:Z2);ROW($2:$5))))}`

Anything with a less than sign you have to put in <code> tags or WordPress will parse it as HTML. I got that less than sign in front of ‘code’ to show up by typing ampersand+l+t+semicolon, which you could use too, but it’s easier to use code tags.

What I really need is a WordPress addin that recognizes when a line starts with = and puts the code tags there automagically.

As a UDF:

Function BestGolf(Rng As Range) As Variant

Const lCount = 4

Const lMany = 5

Dim vScores As Variant

Dim i As Long, j As Long

Dim lMaxQualScore As Long

Dim Result As Variant

vScores = Application.WorksheetFunction.Transpose(Rng)

For i = UBound(vScores) To LBound(vScores) Step -1

If vScores(i, 1) > 0 Then

j = j + 1

Result = Result + vScores(i, 1)

If vScores(i, 1) > lMaxQualScore Then lMaxQualScore = vScores(i, 1)

If j = lMany Then Exit For

End If

Next i

`Select Case j`

Case Is < lMany BestGolf = Result / j Case Is = lMany BestGolf = (Result - lMaxQualScore) / lCount End Select End Function

… mrtThat UDF could also be written as:

Function F_snb_001(c00 As Range)

c01 = c00.Address

F_snb_001 = Evaluate("AVERAGE(IF(COUNT(" & c01 & ")<5," & c01 & ",LARGE((COLUMN(" & c01 & ")=LARGE((" & c01 & ">0)*(COLUMN(" & c01 & ")),ROW($1:$5)))*(" & c01 & "),ROW($2:$5))))")

End Function

snb

I like your array formula, however how can I change it to work vertically on rows rather than columns?

snb

Never mind.

I took the easy way out and just transpose the rows to column:

=AVERAGE(IF(COUNT(A2:A21)0)*TRANSPOSE((ROW(A2:A21))),TRANSPOSE(ROW($1:$5))))*TRANSPOSE(A2:A21),(ROW($2:$5)))))

The array does not come out correctly. One more try:

{=AVERAGE(IF(COUNT(A4:A23)0)*TRANSPOSE((ROW(A4:A23))),TRANSPOSE(ROW($1:$5))))

*TRANSPOSE(A4:A23),(ROW($2:$5)))))}

What formula would I use if I wanted the average of the 5 lowest scores out of the last 10 scores, discarding the oldest score has a new score is added?

Curtis: Here’s how I do the lowest 10 out of the last 20

http://dailydoseofexcel.com/archives/2005/08/18/golf-handicap/