Question

I get the feeling this is close to impossible, but here goes. I have data structured like this:

Test Group 1
pass
fail
pass
fall

Test Group 2
pass
fail

Test Group 3

pass 
fail
fail
pass

I want to be able to paste it into Excel and have Excel summarise the percentage of each test group. So it would end up looking like this:

Test Group 1               Percentage Pass: 50%
pass
fail
pass
fall

Test Group 2              Percentage Pass: 50%
pass
fail

Test Group 3              Percentage Pass: 50%

pass 
fail
fail
pass

BUT as you can see the test group length is not set, and it may vary. I was hoping is that I might be able to create a formula that follows this logic:

if( A<n> contains "Test")

count A<n> +1 until A<n> contains "Test"

It seems like I'm asking a lot from Excel formulas. I have spent some of today writing a small C# app that will split the configs into separate files so that I could copy and paste separate files into Excel. But it would be great to have fewer steps!

--- UPDATE ----

There were three very interesting approaches to this problem proving nothing is impossible :p

I wanted a solution that allowed me to copy and paste results in and see a load of percentages pop up so I was always sort of looking for a formula solution HOWEVER, please take the time to look at pnuts and Jerrys answers as they reveal some useful features of Excel!

chuffs answer was the one I was looking for and it worked out of the box. For anyone who wants to delve deep into how it works and why, I broke the formula down into steps and filled in some help information. The key to these formulas is combining MATCH, OFFSET and the slightly more obvious SEARCH / FIND / LEFT (I used to use IFERROR(FIND type approach, LEFT seems cleaner :) )

Do look at the documentation for these formulas but to see it all in action with some examples see the Google Spreadsheets I created detailing chuffs answer:

https://docs.google.com/spreadsheet/ccc?key=0AqODI11eAjtldDhDd2dBcFhpZW9SXzEybGtMUWMwM3c#gid=0

---P.S--- For the record I did actually create a C++ program to prettify my data and ouput it as .csv files. If I had had this info I wouldn't have bothered but am glad I tried both routes, it was a fun learning adventure.

Was it helpful?

Solution

A single, array-formula solution to this problem is possible. It requires only that a stop value "Test" be added at the bottom of your column of data.

Assuming your data are in the range A2:A18, here is the formula that would compute the average in cell B2:

  =IF(LEFT(A1,4)="Test",
      COUNTIF(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1),"pass")
          / COUNTA(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1)),
      "")

The key parts of the formula are expressions that calculate the ranges for the two count functions, COUNTIF and COUNTA.

The COUNTIF function - which counts the number of passes in a group - takes two arguments, the range for the count and the condition to be met by cells counted.

I use the OFFSET function to provide the count range. OFFSETtakes five arguments:

  • An anchor cell (if a range is provided, the function only uses the top left cell in the range).
  • The number of rows below (+) or above (-) the anchor cell that the range to be returned will begin.
  • The number of columns to the right (+) or left (-) of the anchor cell for the start of the return range.
  • The number of rows to return.
  • The number of columns to return.

For example, OFFSET(A1,5,2,4,1) will return the range C6:D9.

In the formula, the anchor cell is A1, the row offset is 1 and the column offset is 0, in other words, the start of the range to return is A2.

The number of rows to return is computed by the MATCH function. For the calculation of the average for the first test group, MATCH looks in the range A2:A18 for the row of the first cell that starts with the word 'Test'. A2 is the cell in the pass/fail column just below the cell that starts the test group.

The last cell in the column is A18, which has been added to the data and contains the word 'Test'. This prevents the formula from returning an error for the last test group. Otherwise, the match would return an error because it could not find another occurrence of Test beyond the start of the final group.

Also note that the anchor points for the match range, i.e., $A2:$A$18, leaves unanchored the row reference to the top of the range (the 2 in A2). That's so the range will adjust downward as the formula is copied down so as to find the next, not the previous, occurrence of 'Test'.

Finally, I decrease the number of return rows by 1 to exclude the Text that MATCH found, which belongs to the next group.

The COUNTA functions - which counts the total number of passes and fails in a group - uses the same OFFSET/MATCH expression to get the range for the group.

This is an array formula and so must be entered with the Control-Shift-Enter key combination. Copy the formula down to the bottom of the data (excluding the cell with the 'Test' stop value) to calculate the averages for each group.

For convenience, here is the formula without the breaks shown above. It can be directly pasted into the worksheet (remembering to confirm it with Control-Shift-Enter).

  =IF(LEFT(A1,4)="Test",COUNTIF(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1),"pass")/COUNTA(OFFSET(A1,1,0,MATCH("Test*",$A2:$A$18,0)-1,1)),"")

spreadsheet result

OTHER TIPS

Basically Subtotal will meet the requirement, provided some fairly tedious layout adjustments are acceptable.

Preparation:
Assuming Test Group 1 is in A1, insert Row1 and ColumnA, with in A2 =IF(LEFT(B2,1)="T",B2,"") and in C2 =IFERROR(MATCH(B2,{"fail","pass"},0)-1,"") and both formulae copied down as required. (And change fall to fail in source!)

Subtotal:
Select A:C, Data > Outline – Subtotal, At each change in: (1) Test Group 1, Use function: Average, Add subtotal to: check (Column C), uncheck Summary below data, OK.

Tidy up:
1. Move A3:C3 to A1 and A2:C2 to A3.
2. Filter A:C and for ColumnB, Text Filters, Contains add Test, OK.
3. In C3 put ="Percentage Pass: "&C4*100&"%" and copy down to last row numbered in blue (should show #DIV/0!).
4. Highlight A:C for all the rows numbered in blue and embolden.
5. Hide ColumnA and, optionally, hide or delete Rows1:2.
6. Take off filter selection.

Hopefully with preparation as on the left the result would be similar to as shown on the right:

SO16859574 first example


Example re comment to @Jerry's answer:

SO16859574 second example

There are many ways to tackle this -- one possible easy solution is to add a column next to your pass/fail column that says (assuming column A):

=IF(A1="pass",100,0)

if you do that, then the average of those values would be equal to the percentage pass.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top