Excel: What determines evaluation order in a formula? - excel

I have a worksheet with the following contents in A1:G1
7 8 4 2 9 11 10
Formula
=SUMPRODUCT(MIN($B1:$G1-$A1)) (1)
evaluates to -5,
=SUMPRODUCT(ABS($B1:$G1-$A1)) (2)
evaluates to 18. But
=SUMPRODUCT(MIN(ABS($B1:$G1-$A1))) (3)
gives #VALUE!.
To try to understand the issue, I use Formula Auditing -> Evaluate Formula.
In the formulas that work (1 and 2), $A1 is evaluated (underlined) first.
In the formula that doesn't work (3), $B1:$G1 is evaluated (underlined) first.
What is the reason for the error, and the different behavior among formulas?

As per my comment, to get the smallest difference between A1 and B1:G1 without using an "array entered" formula you can use INDEX to do what you were trying to do with SUMPRODUCT, i.e.
=MIN(INDEX(ABS($B1:$G1-$A1),0))

It looks like you are using the SUMPRODUCT function to make this formula work as an array formula and that Excel is not calculating your third formula as an array, giving you a #VALUE error when the formula is entered in column A. It did not give me this error in the columns B through G, but it also did not calculate as an array. Entering your formula as an array formula by pressing Shift+Ctrl+Enter after typing in your formula will fix this. You can also get the same result using a simpler formula:
=MIN(ABS($B1:$G1-$A1))
Once this is entered as an array formula, you will be able to step through the evaluation and see it working correctly.
More info on arrays here: http://office.microsoft.com/en-us/excel-help/introducing-array-formulas-in-excel-HA001087290.aspx

Summarizing the comments by Brad and barry houdini (originally this):
The documentation says the ABS takes a number as its input, that MIN takes an arbitrary number of numbers, and SUMPRODUCT takes an arbitrary number or arrays. Seems like when the ABS is nested so deep it defaults to taking the number and can't figure out how to return an array.
So to counteract that we can use INDEX round ABS and get the correct result without "array entry" and without SUMPRODUCT, i.e. =MIN(INDEX(ABS($B1:$G1-$A1),0)).
This shows the right way of entering the formula, and it explains the cause of the error.

I think you were on course to investigate this using 'Formulas > Evaluate Formula'
The results are for typical math operations: functions are evaluated from the inside out.
Because =SUMPRODUCT(MIN(ABS($B1:$G1-$A1))) is not forced to evaluate as an array $B1:$G1 will return the value from that array from the same column from where the calling cell is located. I.e. if B2 = then $B1:$G1 will return B1, if A2= $B1:$G1 then it will try to return A1 but there is nothing to return so it gives you the #VALUE error.

Related

In Excel, can I sum a column of cells based on whether or not a given value is in each of the rows?

Within Excel, is there an array formula or something else that could shorten the formula below? This is only an example going through 12 rows. The actual formula would have thousands of rows, which is why I'd like to find a way to write this formula much shorter. I've considered and tried SUMIF and SUMPRODUCT in addition to what's below, but I haven't found a way for it to check for a specified value in multiple columns, and then doing that for many rows, like a FOR loop would do. The below formula is in Cell J3. I have attached an image of the spreadsheet example.
=SUM(
IF(ISNUMBER(MATCH($I$3,$B3:$E3,0)),$F3,0),
IF(ISNUMBER(MATCH($I$3,$B4:$E4,0)),$F4,0),
IF(ISNUMBER(MATCH($I$3,$B5:$E5,0)),$F5,0),
IF(ISNUMBER(MATCH($I$3,$B6:$E6,0)),$F6,0),
IF(ISNUMBER(MATCH($I$3,$B7:$E7,0)),$F7,0),
IF(ISNUMBER(MATCH($I$3,$B8:$E8,0)),$F8,0),
IF(ISNUMBER(MATCH($I$3,$B9:$E9,0)),$F9,0),
IF(ISNUMBER(MATCH($I$3,$B10:$E10,0)),$F10,0),
IF(ISNUMBER(MATCH($I$3,$B11:$E11,0)),$F11,0),
IF(ISNUMBER(MATCH($I$3,$B12:$E12,0)),$F12,0),
IF(ISNUMBER(MATCH($I$3,$B13:$E13,0)),$F13,0),
IF(ISNUMBER(MATCH($I$3,$B14:$E14,0)),$F14,0))
Use SUMPRODUCT like this:
=SUMPRODUCT($F$3:$F$14*(MMULT(N($B$3:$E$14=I3),TRANSPOSE(COLUMN($B$3:$E$14)^0))>0))
This is an array formula and it needs to be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode.
Improved solution
=SUMPRODUCT($F$3:$F$14,CEILING(((($B$3:$B$14=$I3)+($C$3:$C$14=$I3)+($D$3:$D$14=$I3)+($E$3:$E$14=$I3))/4),1))
Idea : 4 is the number of rows/week. Use ceiling() to normalize value instead of int() n sqrt().
Expansion note : just add another row condition & adjust 4 to the number of rows.
Past solution (for reference)
=SUMPRODUCT($F$3:$F$14,INT(SQRT(INT(SQRT(($B$3:$B$14=$I3)+($C$3:$C$14=$I3)+($D$3:$D$14=$I3)))+($E$3:$E$14=$I3))))
should do.
idea : while $B$3:$B$14=$I3 part is creating an array of 0 n 1, the INT() n SQRT() function 'force' the '+' sum to become 1 even if there is more than 1 match in the same month.
please share if it works/not. (:
p/s : (note for expansion) Upon dissecting the int() and sqrt() function, you can see that sqrt(3)=1.73205 , sqrt(2)1.414213, sqrt(1)=1 and its int() results the same value (1) . So let say you want to add more rows, just use 'bundle' 3 rows together in one int(sqrt(__)) function, recursively.

Search function with list of text values fails

I use formula =SEARCH({"N.","No.","#"},D5) and it fails if doesn't fit first option "N." how can I fix it?
Using =SEARCH({"N.","No.","#"},D5) formula when you will see how the formula calculates the result using Evaluate Formula, you'll notice
evaluates to
That means formula is searching only for "N."
Therefore to search for the existence of "N.","No.","#" in a cell, number of approaches are available like:
1. =IF(COUNT(SEARCH({"N.","No.","#"},D5)),1,"")
This formula will give 1 if any of the string in the cell exists.
2. =SUMPRODUCT(--ISNUMBER(SEARCH(find_text,D5)))>0
This formula will give TRUE if any of the three string exists else FASLE.

Average a list of numbers if greater than 0

How do I average a list of numbers whose values are greater than 0? I know I can use AVERAGEIF function in Excel
My data is located in A2, A5, A6, A10, A17.
I only want to average it if the data is greater than 0.
Since my data is not an range, I am not able to use AVERAGEIF Function range.
Need some help on this.
EDIT
For example,
I tried with three numbers:
1) 98.068 and 98.954 and 0 so my forumla looked like this:
=AVERAGE(IF(N(OFFSET(A2,{0,5,10},))>0,N(OFFSET(A2,{0,5,10},))))
The answer came out as 99.106. Not sure why.
A few options:
1)=SUM(SUMIF(INDIRECT({"A2","A5","A6","A10","A17"}),">0"))/SUM(COUNTIF(INDIRECT({"A2","A5","A6","A10","A17"}),">0"))
2)=AVERAGE(IF(N(INDIRECT({"A2","A5","A6","A10","A17"}))>0,N(INDIRECT({"A2","A5","A6","A10","A17"}))))
3)
=AVERAGE(IF(N(OFFSET(A2,{0,3,4,8,15},))>0,N(OFFSET(A2,{0,3,4,8,15},))))
2) and 3) must be committed as array formulas**
Regards
(0) A simple method
=SUM(A2*(A2>0),A5*(A5>0),A6*(A6>0),A10*(A10>0),A17*(A17>0))/SUM(A2>0,A5>0,A6>0,A10>0,A17>0)
(4) A more general method
=SUM((A1:A20>0)*A1:A20*(ADDRESS(ROW(A1:A20),1,4)={"A2","A5","A6","A10","A17"}))/
SUM((A1:A20>0)*(ADDRESS(ROW(A1:A20),1,4)={"A2","A5","A6","A10","A17"}))
The second one is an array formula and must be entered with CtrlShiftEnter
If it's possible to have text in the cells rather than numbers, then this should replace the first formula:-
=SUM(N(A2)*(A2>0),N(A5)*(A5>0),N(A6)*(A6>0),N(A10)*(A10>0),N(A17)*(A17>0))/SUM(N(A2)>0,N(A5)>0,N(A6)>0,N(A10)>0,N(A17)>0)
(I haven't used N in the > brackets in the numerator because I reason that if A2 etc. is text, the product will always be zero)
I can't persuade N to work with arrays in the second formula, so at the moment I have the rather lengthy
=SUM((IF(ISNUMBER(A1:A20),A1:A20,0)>0)*IF(ISNUMBER(A1:A20),A1:A20,0)*(ADDRESS(ROW(A1:A20),1,4)={"A2","A5","A6","A10","A17"}))/
SUM((IF(ISNUMBER(A1:A20),A1:A20,0)>0)*(ADDRESS(ROW(A1:A20),1,4)={"A2","A5","A6","A10","A17"}))
but I have tested it on text values and negative numbers and it does seem fine.
The only exception is if one of the cells contains TRUE. In this case the first formula will count it as 1, the second formula will ignore it.

I want to wrap an excel formula that returns an array of values so it replaces 0 values with NA()

I have a formula that I am using in excel. The formula returns an array of values in the form of a column. I only know how to use an IF statement on a cell or a formula that returns one cell. However, I don't know how to apply it to get it to replace all the 0 values by NA() in the array returned by the formula. I want to wrap the formula using the IF statement.
It is a Reuters formula : =IF(RData(D17:D26;H16) = 0; NA(); RData(D17:D26;H16)), but it does not work at all.
RData(D17:D26;H16) returns the following column
H16 contains: AST_SWPSPD
D17:D26 contains the following RIC Codes:
BMPS2YEUAM=R
BMPS3YEUAM=R
BMPS4YEUAM=R
BMPS5YEUAM=R
BMPS7YEUAM=R
BMPS10YEUAM=R
BMPS20YEUAM=R
BMPS30YEUAM=R
The resulting column is the following
201.7
499.5
389.2
470.6
306.8
0
0
525.3
525.3
525.3
I want to get rid of the zeros and replace them with NA
Is that possible?
Thank you.
It should be exactly the same. Lets pretend your formula is F (but it would be much better if you added your actual formula or something similar to your question)
=IF(F=0, NA(), F)
Will work even if F is returning an array. Just replace F with your entire formula and don't forget to press ctrl+shift+enter
Thank you all for your input,
I found a way to go around it, simply by returning one value at a time and wrapping it with the IF statement.
So it becomes: =IF(RData(D17;$H$16)=0;NA(); RData(D17;$H$16))
I am fixing H16 because it contains the argument needed for the formula.
This way it works.
Instead of using =IF(RData(D17;$H$16)=0;NA(); RData(D17;$H$16)) you can also use =IFERROR(1/(1/(RData(D17;$H$16)));NA())
This way, your function gets only called once, which will reduce calculation time.

VLOOKUP with two criteria?

Is there a formula that returns a value from the first line matching two or more criteria? For example, "return column C from the first line where column A = x AND column B = y". I'd like to do it without concatenating column A and column B.
Thanks.
True = 1, False = 0
D1 returns 0 because 0 * 1 * 8 = 0
D2 returns 9 because 1 * 1 * 9= 9
This should let you change the criteria:
I use INDEX/MATCH for this. Ex:
I have a table of data and want to return the value in column C where the value in column A is "c" and the value in column B is "h".
I would use the following array formula:
=INDEX($C$1:$C$5,MATCH(1,(($A$1:$A$5="c")*($B$1:$B$5="h")),0))
Commit the formula by pressing Ctrl+Shift+Enter
After entering the formula, you can use Excel's formula auditing tools to step through the evaluation to see how it calculates.
SUMPRODUCT definitely has value when the sum over multiple criteria matches is needed. But the way I read your question, you want something like VLOOKUP that returns the first match. Try this:
For your convenience the formula in G2 is as follows -- requires array entry (Ctrl+Shift+Enter)
[edit: I updated the formula here but not in the screen shot]
=INDEX($C$1:$C$6,MATCH(E2&"|"&F2,$A$1:$A$6&"|"&$B$1:$B$6,0))
Two things to note:
SUMPRODUCT won't work if the result type is not numeric
SUMPRODUCT will return the SUM of results matching the criteria, not the first match (as VLOOKUP does)
Apparently you can use the SUMPRODUCT function.
Actually, I think what he is asking is typical multiple results display option in excel. It can be done using Small, and row function in arrays.
This display all the results that matches the different criteria
Here is an answer that shows how to do this using SUMPRODUCT and table header lookups. The main advantage to this: it works with any value, numeric or otherwise.
So let's say we have headers H1, H2 and H3 on some table called MyTable. And let's say we are entering this into row 1, possibly on another sheet. And we want to match H1, H2 to x, y on that sheet, respectively, while returning the matching value in H3. Then the formula would be as follows:
=INDEX(MyTable[H3], ROUND(SUMPRODUCT(MATCH(TRUE, (MyTable[H1] & MyTable[H2]) = ($x1 & $y1),0)),0),1)
What does it do? The sum-product ensures everything is treated as arrays. So you can contatenate entire table columns together to make an array of concatenated valued, dynamically calculated. And then you can compare these to the existing values in x and y- somehow magically you can compare the concatenated array from the table to the individual concatenation of x & y. Which gives you an array of true false values. Matching that to true yields the first match of the lookup. And then all we need to do is go back and index that in the original table.
Notes
The rounding is just in there to make sure the Index function gets back an integer. I got #N/A values until I rounded.
It might be more instructive to run this through the evaluator to see what's going on...
This can easily be modified to work with a non table - just replace the table references with raw ranges. The tables are clearer though, so use them if possible. I found the original source for this here: http://dailydoseofexcel.com/archives/2009/04/21/vlookup-on-two-columns/. But there was a bug with rouding values to INTs so I fixed that.

Resources