I have been working on an attendance sheet and trying to make the monthly reports automatic. I have asked my previous question on the same issue and got the idea to accomplish the task.
But now I have stuck at one place. I have this below formula:
=COUNTIFS(C5:C27,">0", E5:E27,"G", F5:F27,"CAT1")
The value in cell "C" in the above is coming from the below formula (in cell "C")
=IF((COUNTIF(G5:AK5,"p"))>0,1,0)
I had to add this extra column ("C") only to supply input to my fist formula. My question is - "Can we merge the IF function inside the COUNTIFS to get the result in one go and to eliminate the use of an extra column (column C)"?
To perform these cell reference acrobatics you will likely need to switch to an array formula. Array formulas chew up calculation cycles logarithmically so it is good practise to narrow the referenced ranges to a minimum. A 'helper' column such as you've used in column C can generally reduce calculation cycles and make a worksheet more 'user friendly'.
A COUNTIFS function requires that the ranges being examined are not only the same size but also the same shape. Looking at G5:AK5 is not the same as looking at E5:E35 even though they contain the same number of cells¹.
In the sample data below, you formula is in A1 and uses the 'helper column' C. My array formula is in A2 and does not consider column C ahough it incorporated the logic.
The array formula in A2 is:
=SUM(IF(E5:E27 = "G", IF(F5:F27 = "CAT1", SIGN(COUNTIFS(OFFSET($G$5, ROW($1:$23)-1, 1, 1, 31), $I2)))))
Array formulas need to be finalized with Ctrl+Shift+Enter↵. Once entered into the first cell correctly, they can be filled or copied down or right just like any other formula.
¹Some functions not only accept but welcome cell ranges that are the same number of calls but transposed. Offsetting or staggering the ranges is also an option if the cell ranges are the same size. In difficult cases the TRANSPOSE function can be helpful.
Related
I want to get the count of cells used in an excel function.
For example say I have a sum function ='CV'!D11+Farmer!D11+'County'!D11+Rt!D11+WT!D11+'Country'!D11
I need a function that will tell me how many cells were used to get the total sum. In this case it is 6. The tricky part is if one of the cells used is blank I do not want it counted. For instance say cell D11 on the Farmer sheet is blank I do not want it counted in the total. So the total should be 5.
Use COUNT:
=COUNT('CV'!D11,Farmer!D11,'County'!D11,Rt!D11,WT!D11,'Country'!D11)
It will only count the cell if it has a number
You should really try to collate all your data in to a single sheet before running calculations. For the sake of example, I'll assume you have it in the range A1:A5, then you can add handling of the various cases using array formulas:
Get the count of non-empty cells (the ISBLANK function is untrustworthy in my experience): {SUM(IF(LEN(A1:A5)>0,1,0))}
Get the sum of those cells: SUM(A1:A5)
(must use Ctrl+Shift+Enter to enter the formula as an array formula, you will know it worked if the formula shows like {IF(...)} with the curly brackets)
Because blank/missing values are treated implicitly as 0 in the SUM function, this case is simple. If you have other validations then you'd have to write an array formula for the summation as well. For example, only including numbers between a min and max threshold (e.g. if you want to exclude outliers):
{SUM(IF(AND(A1:A5 >= yourMinValue, A1:A5 < yourMaxValue), A1:A5, 0)}.
If I understand your question correctly, you want to literately count the number of cells used in a formula which in your example is summing 6 values from 6 different locations.
I used the following example to demonstrate my solution:
The sum of =A1+B1+C1+D1+E1+F1 is 10 where cell C1 has a 0 value in it but cell E1 is blank.
Using the following array formula I was able to count the number of cells that have a value other than 0:
=SUMPRODUCT(IFERROR(ABS(N(INDIRECT(TRIM(MID(SUBSTITUTE(RIGHT(FORMULATEXT(A3),LEN(FORMULATEXT(A3))-1),"+",REPT(" ",100)),100*ROW(INDIRECT("1:"&LEN(FORMULATEXT(A3))))-99,100)))))>0,0)*1)
Please note you MUST press Ctrl+Shift+Enter upon finishing the formula in the formula bar otherwise they will not function correctly.
The logic is to use a combination of TRIM+MID+SUBSTITUTE+RIGHT+FORMULATEXT+REPT+ROW+INDIRECT to extract the cell addresses from the original formula, then use INDIRECT to convert the cell address into the values stored in those cells, then use a combination of IFERROR+ABS+N to find out if any of these values are not 0, and lastly use SUMPRODUCT to add up all the TRUE results.
It is obvious that there are a couple limitations of my solution:
If your actual formula is not strictly in the form of A+B+C+D+E+F, then my SUBSTITUTE part of formula will need further modification;
The formula will treat cells containing 0 as blank and does not include them in the count.
Let me know if you have any questions. Cheers :)
I am wondering, if there is a general way to express, that only visible rows of a formula should be taken into account.
If I have for example a formula sumif($E5:$E100; "ABC"; $F5:F100) it would be very helpful, if there would be a way to express, that the given ranges should only take visible cells into account. I could imagine that a kind of prefix can be specified to a range construct like % or that like. For example the formula then would look like sumif(%$E5:%$E100; "ABC"; %F5:%F100) to make clear, that in the given ranges only visible rows should be taken into account.
Same would then for example be for sum(%A1:%A100) which would mean, that in the range between A1 and A100 only visible cells should be taken to sum up the cells.
The point is, that this construct could be taken inside any kind of formula, no matter what it is.
Thanks in advance
Georg
Generically to sum sumrange based on a match in criteriarange.....but only for visible rows you can use this formula: =SUMPRODUCT((criteriarange=criteria)+0,SUBTOTAL(109,OFFSET(sumrange,ROW(sumrange)-MIN(ROW(sumrange)),0,1,1))) The first part (criteriarange=criteria)+0 just checks the criteria for each row and returns 1 for a match or 0 OFFSET returns an "array of ranges" with each range in this case being a single cell from the sum range. SUBTOTAL can process that and with the sum function (109) gives the "sum" (i.e. the value) of each cell, only when visible. – SUMPRODUCT then multiplies the two ranges and sums the result, effectively giving you the sum of visible rows where the criteria matches
Try This
=SUMPRODUCT(($E$5:$E$100="ABC")+0,SUBTOTAL(109,OFFSET($F$5:$F$100,ROW($F$5:$F$100)-MIN(ROW($F$5:$F$100)),0,1,1)))
I would like to create a table with products and formulas on a sheet (Sheet2). For different products, different formulas apply.
I would like to retrieve the formula from that table but use the row numbers from the row in Sheet1
How do I enter a formula which is evaluated with the correct row numbers from Sheet1.
I have a UDF eval that can evaluate a text string:
=eval(vlookup(Product;Table;2;false)
The formula retrieved from the Table should use the row number of the actual row that the eval() is on.
I tried the following:
="D"&ROW(Sheet2!$A16)&"/G"&ROW(Sheet2!$A16)&"/F"&ROW(Sheet2!$A16)&"*5"
This retrieves the formula but the eval() does not calculate the result.
In your example, product is located on Sheet2 in the 16th row of the first column of table. If you want the 16th row on the worksheet, you can use the MATCH function on a full column reference, discarding the structured references of the ListObject table or you can use MATCH on the structured table reference and compensate for the 'position within' table by adjusting by the table header row.
That's probably confusing so here is an example.
To find the actual row-on-the-worksheet where bcd resides you would use one of these formulas.
=MATCH("bcd", Sheet2!B:B, 0)
=MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers])
The first simply returns row 6 on the worksheet. The second returns 2 since bcd is in the second row of the ListObject's .DataBodyRange property and this is adjusted by the row that the .HeaderRowRange property is in; e.g. 2 + 4 = 6.
Now that everything is clear, all you need to do is use the result from one of those formulas as the row_number parameter in an INDEX function.
=INDEX(D:D, MATCH("bcd", Sheet2!B:B, 0))/
INDEX(G:G, MATCH("bcd", Sheet2!B:B, 0))/
INDEX(F:F, MATCH("bcd", Sheet2!B:B, 0))*5
'or,
=INDEX(D:D, MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers]))/
INDEX(G:G, MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers]))/
INDEX(F:F, MATCH("bcd", Table2[a], 0)+ROW(Table2[#Headers]))*5
Your own formula could have worked with a series of INDIRECT functions that convert constructed strings to actual cell references. However, INDIRECT is considered volatile and best avoided if possible.
=INDIRECT("D"&ROW(Sheet2!$A6))/INDIRECT("G"&ROW(Sheet2!$A6))/INDIRECT("F"&ROW(Sheet2!$A6))*5
This solution is based on the capability of Excel to reference the cells in R1C1 style. In order to use it, you will have to go to File -> Options -> "Formulas" tab, and check the box "R1C1 reference style" in "Working with Formulas" group.
In addition, your eval() function will have to be able to evaluate such kind of formulas.
Once, all of these is done, you only have to retrieve the formula.
In order to make the things clear, I will focus on an example.
The table below is the contents of Sheet1 (the "Database" of products).
The column "Formula" contains the relevant formula:
for apple: RC[-2]+RC[-1]
for banan: RC[-2]*RC[-1]
for lemon: RC[-2]/RC[-1]
The table below is the contents of Sheet2:
The column "Formula" here contains the formula, retrieved from Sheet1. The formula of the column "Formula" is as follows:
=FORMULATEXT(INDEX(Sheet1!R2C1:R4C4,MATCH(RC[-3],Sheet1!R2C1:R4C1,0),4))
The description of each of the functions, used here (formulatext, index and match) can be found in Excel help.
As it can be seen, the retrieved formula, represented in R1C1 style is correct in context of Sheet2, were the products are arranged differently, and may appear more than once. The only remaining work to do is to apply the eval() function, after it was adapted to evaluate R1C1-style referenced formulas.
I hope it helps.
I want to use SUBTOTAL to calculate the mean within a range without hard coding in the cell references.
I an currently using the standard:
=SUBTOTAL(1, A2:A11)
But I want Excel to recognise which cells in column A start and end possessing values. So I can specify cell A11 in a separate cell using:
=ADDRESS(MATCH(9.99999E+307, A:A), 1)
Which returns "$A$11". However, If I combine the above equations thus:
=SUBTOTAL(1, A2:ADDRESS(MATCH(9.99999E+307, A:A), 1))
I get an error. I have also tried INDIRECT in combinations with these but that does not work either.
Use the INDEX function to supply the latter half of the cell range.
=SUBTOTAL(1, A2:INDEX(A:A, MATCH(1e99, A:A)))
I want to calculate the average over a range (B1:B12 or C1:C12 in the figure), excluding:
Cells not being numeric, including Empty strings, Blank cells with no contents, #NA, text, etc. (B1+B8:B12 or C1+C8:C12 here).
Cells for which corresponding cells in a range (A1:A12 here) have values outside an interval ([7,35] here). This would further exclude B2:B3 or C2:C3.
At this point, cells in column A may contain numbers or have no contents.
I think it is not possible to use any built-in AVERAGE-like function. Then, I tried calculating the sum, the count, and divide. I can calculate the count (F2 and F7), but not the sum (F3), when I have #N/A in the range, e.g.
How can I do this?
Notes:
Column G shows the formulas in column F.
I cannot filter and use SUBTOTAL.
B8:C8 contain Blank cells with no contents, B9:C9 contain Empty strings.
I am looking for (non-user defined) formulas, i.e., non-VBA.
From
https://stackoverflow.com/a/30242599/2103990:
Providing you are using Excel 2010 and above the AGGREGATE
function
can be optioned to ignore all errors.
=AGGREGATE(1, 6, A1:A5)
You can accomplish this by using array formulas based upon nested IFs to provide at least part of the criteria. When an IF resolves to FALSE it no longer process the TRUE portion of the statement.
The array formulas in F2:F3 are,
=SUM(IF(NOT(ISNA(B2:B13)), (A2:A13>=7)*(A2:A13<=35)*(B2:B13<>"")))
=SUM(IF(NOT(ISNA(B2:B13)), IF(B2:B13<>"", (A2:A13>=7)*(A2:A13<=35)*B2:B13)))
The array formulas in F7:F8 are,
=SUM(IF(NOT(ISNA(C2:C13)), (A2:A13>=7)*(A2:A13<=35)*(C2:C13<>"")))
=SUM(IF(NOT(ISNA(C2:C13)), IF(C2:C13<>"", (A2:A13>=7)*(A2:A13<=35)*C2:C13)))
Array formulas need to be finalized with Ctrl+Shift+Enter↵. Once entered correctly, they can be filled down like any other formula if necessary.
Array formulas increase calculation load logarithmically as the range(s) they refer to expand. Try to keep excess blank rows to a minimum and avoid full column references.
You can get the average of your "NA" column values in one fairly simple formula like this:
=AVERAGE(IF(
(
($A$2:$A$13>=$F$2)*
($A$2:$A$13<=$F$3)*
ISNUMBER(B2:B13)
)>0,
B2:B13))
entered as an array formula using CtrlShiftEnter↵.
I find this to be a very clear way of writing it, because all your conditions are lined up next to each other. They're "and'ed" using the mathematical operator *; this of course converts TRUE and FALSE values to 1's and 0's, respectively, so when the and'ing is done, I convert them back to TRUE/FALSE using >0. Note that instead of hard-coding your thresholds 7 and 35 (hard-coding literals is usually considered bad practice), I put them in cells.
Same logic for your sum and your count; just replace AVERAGE with SUM and COUNT, respectively:
=SUM(IF((($A$2:$A$13>=$F$2)*($A$2:$A$13<=$F$3)*ISNUMBER(B2:B13))>0,B2:B13))
=COUNT(IF((($A$2:$A$13>=$F$2)*($A$2:$A$13<=$F$3)*ISNUMBER(B2:B13))>0,B2:B13))
though a more succinct formula can also be used for the count:
=SUM(($A$2:$A$13>=$F$2)*($A$2:$A$13<=$F$3)*ISNUMBER(B2:B13))
The same formulas can be used to average/sum/count your "blank" column. Here I just drag-copied them one column to the right (column G), which means that all instances of B2:B13 became C2:C13.