Reputation: 715
Could not find a suitable solution, hence this post.
Have 2 sheets - Attendance & Payroll where attendance is filled in a pivoted manner (see sample).
For a given date range, I want to count the number of "Absent" days for the staff. The Non-Array-Formula (in Payroll column "Absent") below does that. Note: column A with staff ids is a dynamic list even though its fixed in the sample.
How this formula works:
Note: there is no guarantee that payroll-staffids order and attendence-header-staffids are both in same order -> that's why each staffid is mapped MATCHed and OFFSET.
=COUNTIF(OFFSET(INDIRECT(Settings!$B$13),0,MATCH(A5,Attendance!$B$1:$1,FALSE)),"Absent")
Sample sheet here.
Upvotes: 0
Views: 434
Reputation: 715
=ArrayFormula(VLOOKUP(A5:A15, TRANSPOSE({INDIRECT(AttHeader,FALSE);MMULT(TRANSPOSE(SIGN(ROW(INDIRECT(AttUnitMatrix)))),IF(INDIRECT(AttData,FALSE)="Absent",1,0))}),2,FALSE))
See linked sample sheet in OP. For defined names; see the Settings sheet. All ranges are computed separately to reduce the size of the formula.
1) Start operating in "block mode", ignoring order of staff-ids. "AttData" is the string representation of the data block and mapped to 1 if "Absent" else 0.
IF(INDIRECT(AttData,FALSE)="Absent",1,0)
2) This matrix is multiplied by a unit row matrix from range string "AttUnitMatrix"
TRANSPOSE(SIGN(ROW(INDIRECT(AttUnitMatrix))))
3) MMULT returns a row of "Absent" counts
4) { } is used to prepend the staff-ids to the "Absent" counts for a 2 row matrix.
{INDIRECT(AttHeader,FALSE);MMULT(...)}
5) TRANSPOSE result to be accessed by VLOOKUP (2 column matrix)
6) VLOOKUP takes care of out of order staff-ids by matching the key-staff-ids to the generated row matrix of (staff-id / absent-count) pairs.
fireworks ... pat on my back :)
In this case and others, and I've sent feedback to Google about this, a feature request "Named Formulas" akin to "Named Ranges", to be used in standard formulas. This is WITHOUT resorting to GAS. When formulas become large, this is NOT a luxury, but a NECESSITY. If readers find such a feature useful, please send feedback to Google.
eg: UnitMatrix($1) => TRANSPOSE(SIGN(ROW(INDIRECT($1))))
MMULT(UnitMatrix(AttUnitMatrix),IF(INDIRECT(AttData,FALSE)="Absent",1,0))
Upvotes: 0