Using LET with COUNTIF and Array, e.g. MAP - excel-formula

Edit: 2022-07-26: found this web page that gives background why COUNTIF isn't working: https://exceljet.net/excels-racon-functions
Original question:
I like to compose a LET-function - based on a MAP-array - and then return the COUNTIF-values (see whole formula at the end of the question)
The simplified version of my problem is:
=LET(figures,{1;10;13;10},COUNTIF(figures,10)) returns #VALUE instead of 2 (row 4 in screenshot)
Whereas e.g.
=LET(figures,{1;10;13;10},ROWS(figures)) returns as expected 4 (row 2 in screenshot).
What works too:
=LET(figures,{1;10;13;10},figures) (row 9 in screenshot)
=COUNTIF(B9#,10) returns 2 as expected (row 14 in screenshot)
So the question is:
How do I have to adjust =LET(figures,{1;10;13;10},COUNTIF(figures,10)) to return the correct value of 2?
Further background:
I am trying to built an answer for How to count items in Excel within a date range or without an end date.
What I would like to do is:
=LET(calculatedAge,MAP(tblData[Start Date], tblData[End Date], LAMBDA(startdate,enddate,ROUND((MIN(IF(ISBLANK(enddate),H$1,enddate),H$1)-startdate)/365,0))), COUNTIF(calculatedAge,$G2))
which returns the #VALUE error as well

It looks like your formula is trying to return an array when COUNTIF is used.
Try using FILTER and then ROW in the LET function.
=LET(figures,{1;10;13;10},filtered,FILTER(figures,figures=10),ROWS(filtered))
And the full formula would be:
=LET(calculatedAge,MAP(tblData[Start Date], tblData[End Date],
LAMBDA(startdate,enddate,ROUND((MIN(IF(ISBLANK(enddate),H$1,enddate),H$1)-
startdate)/365,0))),filtered,FILTER(calculatedAge,calculatedAge=$G2),
ROWS(filtered))

Related

How to find the difference in values for each entry in one of the columns

What formula could I use to find the Average difference for each time there is an entry for column B.
For example in the excerpt below the average would be 7. We would only use rows 2 and 3 because there is an entry in them. If I can I would like to avoid using VBA.
Submitted
Returned
10/2/2022
10/3/2022
10/9/2022
10/17/2022
10/25/2022
10/25/2022
10/9/2022 - 10/3/2022 = 6
10/17/2022 - 10/25/2022 = 8
(6 + 8) / 2 = 7
I tried finding a for each function in excel and I tried using =Average(B-A)
You have several options. Using AVERAGE, you can use the following in cell D1:
=AVERAGE(IF(B2:B5-A2:A5 < 0, "", B2:B5-A2:A5))
This function ignores empty values ("") as part of the average (but AVERAGEA doesn't). The resulting array of IF statement will be the difference in days of the Returned value and the Submitted value if the Returned is not empty, otherwise, it will be an empty string. Empty dates are represented in Excel as 0 and any other non-empty date is a positive number, so B2:B5-A2:A5 < 0 meets our requirement.
Another alternative is to use SUMPRODUCT (in cell D2):
=SUMPRODUCT(B2:B5-A2:A5,--(B2:B5>0))/COUNT(B2:B5)
Note: You cannot use AVERAGEIF or AVERAGEIFS with the input argument: B2:B5-A2:A5 because it is not a range and the first input argument is required to be a range.
Here is the output:

AGGREGATE function not ignoring errors when it should

I need an aggregate function to sum a column depending on what's on the next column. I only want to sum values in front of cells formatted as dates (2nd and 4th rows) which correspond to February only (2nd row).
Here's how the table looks :
Sum (1) | Date (2)
40 February
29,05 19/02/2019
0,00 February
10,00 23/03/2019
10,00 February
17,65 March
0,00 February
I found a way to do this, but this is an array formula, and I have to avoid to enter it with the Control-Shift-Enter key combination.
Here is the working formula I have now (I found part of this formula here: Excel Formula to SUMIF date falls in particular month)
={SUM(IFERROR(IF(MONTH(February_expenses[Date])=2;February_expenses[Sum];0);0))}
This gives the 29.05 expected result. Now, here is what I have for the aggregate function (code 9 is for "sum", code 6 is for "ignoring errors") :
=AGGREGATE(9;6;February_expenses[Sum]/(MONTH(February_expenses[Date])=2))
Which also translates to (highlight + F9 key) :
=AGGREGATE(9;6;{#VALUE!;29,05;#VALUE!;#DIV/0!;#VALUE!;#VALUE!;#VALUE!})
The problem is, this function returns "#VALUE!". I can't figure out why because I indicated the function to ignore errors (code 6). Any idea where I may be wrong ?
The Reference forms of the AGGREGATE function doesn't accept arrays as arguments (unless the array is a range of cells). And the Array forms don't include a SUM function.
If you want to avoid having to use CSE, you can use SUMPRODUCT like this:
=SUMPRODUCT(ISNUMBER(1/(MONTH(February_Expenses[Date])=2))*February_Expenses[Sum])
The 1/(…) converts the FALSE returns to an error to eliminate the non-February months in addition to the real error values.

EXCEL - SUM column if date matches TODAY()

I've tried using SUMIF to obtain my results but it doesn't work properly.
I have a row of dates (XX/XX/XXXX format) and I would like to check this row for the current date.
If the row contains the current date, then I would like to sum the total of that column and row 5-20.
For example - today is 10/13/2016. I would like to search for TODAY() in a certain row (Row 1 for example), and if TODAY() is found, then total this column from row 1 down to row 3.
--A-- --B--
10/13/2016 10/14/16
1 50 10
2 10 4
3 5 6
The result should be 65 only IF the date matches TODAY().
I've also checked on giving the column letter based on the date but with no luck.
Any tips are appeciated! Thank you.
I think you can achieve this with a simple IF and a SUM
i.e. in your example above if you want the result to appear on the bottom row you can just use:
=if(B2=today(), sum(B3:B5), "")
This will display the sum at the bottom of the column for columns where the date = today and a blank in the other columns
You need to use the OFFSET function. You can find the documentation here: https://support.office.com/en-us/article/OFFSET-function-C8DE19AE-DD79-4B9B-A14E-B4D906D11B66
In your particular example the following formula will work:
=SUM(OFFSET(D2, 1, MATCH(B2, $D$2:$F$2, FALSE) - 1, 20))
You can see the formula working below. Assuming you know what the SUM formula is doing, I will explain what the OFFSET formula is doing:
First Parameter: Says start at cell D2
Second Parameter: This is how many row up/down do you want to do. In your case you need start at row below the date so '1' it is.
Third Parameter: This is how many columns to the right do you want to
go. Well the number of columns you want to go is based upon where
your date is. So this uses the match formula to figure out how far
to the right to go.
Fourth Parameter: This is how many row do you want to include. I just picked 20 to include the 20 rows below the selected cell.
You obviously need to modify the parameters a little bit to fit your exact data shape.
So I'll give it a shot:
{=SUM(HLOOKUP(TODAY(),Table_With_Dates_and_Three_Rows_Cell_Reference,{2,3,4}))}
NB: Don't type {} but put the formula inside it and then hit Ctrl+Shift+Enter to create what is called an array formula (it does array calculations element by element then submits the aggregating function value---in this case that is sum).

MATCH and LOOKUP returning unexpected values

UPDATE WITH ANSWER:
I misunderstood the operation of MATCH and LOOKUP; they apparently do not automatically select the last value.
The updated formula is as follows:
=IF(
ISNUMBER( MATCH(2,INDEX(1/($D2=$D$1:$D1),0)) ),
($A2+$B2) - (LOOKUP(2,1/($D2=$D$1:$D1),$A$1:$A1)+LOOKUP(2,1/($D2=$D$1:$D1),$B$1:$B1))
,0 )
The main differences are that MATCH is now MATCH(2,INDEX(1/($D2=$D$1:$D1),0)) and LOOKUP is now LOOKUP(2,1/($D2=$D$1:$D1),$A$1:$A1).
Thanks barry houdini and Nanashi for their help!
I am working on what was supposed to be a simple spreadsheet, but one of my formulas is giving me unanticipated results. A screenshot of my data can be seen below:
![Spreadsheet Screenshot][1]
In column C, I am trying to get the time difference between the previous data point with the same type and the current data point. My formula (formatted for easier reading, and taken at cell C11) is as follows:
=IF(
NOT( ISNA( MATCH($D11,$D$1:$D10,1) ) ),
($A11+$B11)-(
LOOKUP($D11,$D$1:$D10,$A$1:$A10)+LOOKUP($D11,$D$1:$D10,$B$1:$B10)
),FALSE)
The cell numbering changes for the appropriate cell–for example, C10 references $D10 and the range $D$1:$D9, etc.
The conditional (NOT( ISNA( MATCH($D11,$D$1:$D10,1) ) ) checks to make sure that in column C there is a previous value that equals the current one; otherwise it returns FALSE, as it does in rows 1 and 12.
The calculation ($A11+$B11)-(LOOKUP($D11,$D$1:$D10,$A$1:$A10)+LOOKUP($D11,$D$1:$D10,$B$1:$B10) takes the current row date and time and subtracts the date and time in the row corresponding with the previous instance of the same type (the LOOKUP function is supposed to return the last occurrence of a value in an array, according to the documentation).
My issue is this: after row 12, the MATCH and LOOKUP functions are all picking up row 11 as the last row in which column C has the value of 1. I've tried testing them separately, and both functions return their appropriate values from row 11. For example, putting the following formula in E16: =MATCH(1,$D$1:$D16,1) returned 11 when I would expect the value to be 16.
What am I doing wrong?
The problem here is that MATCH is not programmed to return the index of the latest matching value. That said, a formula that gets this for us will solve the problem.
Enter the following formula in C2 and drag down:
=MOD((B2)-INDEX(B:B,SUMPRODUCT(MAX(($D$1:$D1=D2)*ROW($D$1:$D1)))),1)
Broken down, this is what each part does:
=SUMPRODUCT(MAX(($D$1:$D1=D2)*ROW($D$1:$D1))) 'Returns the row of the latest match.
=INDEX(B:B, SUMPRODUCT...) 'Returns the matching cell in Column B.
=MOD(B2 - INDEX(...),1) 'Gets the absolute difference, no need to add A and B.
Result:
Let us know if this helps.
EDIT: Changed formula as per Barry's correction.
Neither MATCH nor LOOKUP will find the "last occurrence" as you require with unsorted data. Try these versions for last row/match:
=MATCH(2,INDEX(1/($D11=$D$1:$D10),0))
=LOOKUP(2,1/($D11=$D$1:$D10),$B$1:$B10)
....for your specific requirement you can get both date and time in one LOOKUP, e.g.
=$A11+$B11-LOOKUP(2,1/($D11=$D$1:$D10),$A$1:$A10+$B$1:$B10)
which explicitly uses the dates in column A - if you have data for every day, so you can always assume that change of day is to the next day then you can leave out the date references and use MOD like this:
=MOD($B11-LOOKUP(2,1/($D11=$D$1:$D10),$B$1:$B10),1)

SUMPRODUCT( SUMIF() ) - How does this work?

Part 1:
I was able to construct a formula that does exactly what I want (from some examples), but yet, I'm unable to figure out how exactly it works. I have, starting with cell A1:
Price $
table 20
chair 10
Invoice Quantity
table 17
chair 1
chair 2
table 3
What I want is the final total (430) for the invoice which is computed as Quantity*Price for each item (17*20 + 1*10 + 2*10 + 3*20). the following formula correctly does this:
=SUMPRODUCT(B6:B9,SUMIF(A2:A3,A6:A9,B2:B3))
I understand the basics of SUMPRODUCT and SUMIF. But here, my argument for SUMIF's range is A2:A3, which makes me think the SUMIF would iterate through A2 and A3, and not through A8:A11 (which is the criteria). What gives?
Edit: the unclear part is, what exactly does SUMIF do (what is its iteration pattern) when the first two arguments are of different dimensions (here, the range is 2 cells while the criteria is 4 cells). Also, what is the "output" of SUMIF? An array? Of what dimensions?
Part 2:
In addition, if I ignored the quantity and simply wanted to add 20 whenever I saw a table and 10 whenever I saw a chair, I figured I would do:
=SUMIF(A2:A3,A6:A9,B2:B3)
But that doesn't work, and I have to enclose it with a SUMPRODUCT() for it to work and correctly evaluate to 60. Enclosing it within a SUM doesn't work either (probably because the SUMIF doesn't return an array?) Why?
I've read a bunch of tutorials and still can't understand this, and would be most grateful for a clear, intuitive explanation for both these cases. Thank you.
SUMIF can produce an array of results. If you take my formula
=SUMIF(A6:A9,A2:A3,B6:B9)
it says
For the criteria in A2 (ie table)
- look at A6:A9
- where table is matched, sum the corresponding value in B6:B9
- returns 20 (ie 17 +0 +0 +3)
- this is stored in the first position of the array
Then for the criteria in A3 (ie chair)
- look at A6:A9
- where table is matched, sum the corresponding value in B6:B9
- returns 3 (ie 0 +1 +2 +0)
- this is stored in the second position of the array
So the end array from the SUMIF is {20:3}
You can see the array result by highlighting the SUMIF formula in Excel's formula bar and then pressing F9
Then use SUMPRODUCT to multiple the count in the SUMIF by the $ values in B2:B3 to get total dollars
={20;3}*{20:10}
=20*20 + 3*10
= 430
Part 1
Rather than
SUMIF(A2:A3,A6:A9,B2:B3)
which produces a four element array of
={20;10;10;20}
(corresponding to table;chair;chair;table)
You should use
SUMIF(A6:A9,A2:A3,B6:B9)
which sums the values in B6:B9 against your two criteria in A2:A3 giving the desired result
={20;3}
(corresponding to table;chair)
and then use SUMPRODUCT to weight your array, ie
=SUMPRODUCT(SUMIF(A6:A9,A2:A3,B6:B9),B2:B3)
={20;3}*{20:10}
=430
Part 2
Use COUNTIF to return an array of the number of chairs and tables and then multiply by the vales using SUMPRODUCT
=SUMPRODUCT(B2:B3,COUNTIF(A6:A9,A2:A3))
={20;10} * {2;2}
=60
Well you only have one minor mistake:
probably because the SUMIF doesn't return an array?
SUMIF can work with arrays, thats why you formula SUMPRODUCT( SUMIF() ) works in first place, to SUMIF show an array you have to select a group of cells (like C6:C9) input the formula and use CTRL+SHIFT+ENTER instead of ENTER only. this generate an "array fomula", identified by curly brackets {} (those can only be entered with CTRL+SHIFT+ENTER, no manualy) and show the array formula and results

Resources