I'm attempting to grab each instance of the largest value within a range and display the five adjacent columns of data associated with each instance.
Sample
I was able to grab the largest data using this:
=IFERROR(LARGE($A$3:$A$100,ROW(1:1)),"NONE")
Unfortunately, I'm unable to figure out how to grab the adjacent data associated with the next instance of the duplicate value.
Note:
The archive table is in ascending order because that is the only way I can think of to ease copying and pasting the latest data.
If you do not want to use a sorted order, you can simply use this array formula at H3 and then auto-fill it to M8:
=IFERROR(INDEX($A$3:$F$18,SMALL(IF($A$3:$A$18=MAX($A$3:$A$18),ROW($1:$16)),ROW(A1)),COLUMN(A1)),"NONE")
This is an array formula and must be confirmed with Ctrl+Shift+Enter!
If you still have any questions, just ask ;)
EDIT:
The core is IF($A$3:$A$18=MAX($A$3:$A$18),ROW($1:$16)) which returns an array of rows and False like {FALSE,2,FALSE,FALSE,5,FALSE.....}. Knowing that SMALL ignores FALSE, You get with SMALL(...,1) the first row with the max value. (this way SMALL(...,2) will output the second row .....).
Using ROW(A1) and COLUMN(A1) as non static ref, you get the k for our SMALL and the column for our INDEX :)
Step 1)
Take your large function and compare it to the max from your source range, if it is less than max display none, if otherwise have it display the max.
Step 2)
Since your data is sorted in ascending order find the position in the range of the first instance of your maximum value.
=MATCH(MAX($A$3:$A$18),$A$3:$A$18,0)
We will use this to return the corresponding values in the adjacent columns by substituting it into an index formula for each column to be returned
=INDEX(B$3:B$18,MATCH(MAX($A$3:$A$18),$A$3:$A$18,0))
Place the above in I3 and copy it to right
Step 3)
Since your Data is sorted in order it means the next row down in column A of the max value will be still max value or end of the list. There for match value need to be increased by 1 for each consecutive row and needs some error handling
So we can use our formula from row 3 and adjust it as follows:
=IFERROR(INDEX(B$3:B$18,MATCH(MAX($A$3:$A$18),$A$3:$A$18,0)+1),"NONE")
OR
=IF(H4="NONE","NONE",INDEX(B$3:B$18,MATCH(MAX($A$3:$A$18),$A$3:$A$18,0)+1)
then change the +1 to a +2 then +3, etc however since we don't know wow many times this process will complete we can use the row reference which you started with and change the formula as follows:
=IFERROR(INDEX(B$3:B$18,MATCH(MAX($A$3:$A$18),$A$3:$A$18,0)+(row()-3)),"NONE")
OR
=IF(H4="NONE","NONE",INDEX(B$3:B$18,MATCH(MAX($A$3:$A$18),$A$3:$A$18,0)+(ROW()-ROW($A$3))))
the -3 being the hardcoded value for your first row of data which could also be changed to -ROW(A3) where A3 is a cell in the first row of your new table.
ERROR CORRECTION
I was adding the row bump to the match portion inside the match formula. This was a mistake. adding the +1,+2 or whatever needs to be added to the results of the match formula but still within the index formula. I have updated the formulas above to reflect this.
Related
So I have data consisting of the following:
there are multiple more rows.
Im trying to retrieve the last 5 values in a row, for further use.
I can do this with a simple INDEX(MATCH()) setup, however that doesn't ignore the blank cells, which I would like it to do. It does successfully detect the first nonblank cell and returns that, however when it's blank in the middle of the 5 most recent, it doesn't remove that.
something like this is what it does now:
however i want it to come back in this format:
and so on. A blank could occur at any position, and there may not always be 5 scores available to retrieve.
TIA
You could use the following array-formula (entered with ctrl+shift+enter in older Excel versions):
=INDEX(1:1,AGGREGATE(14,6,COLUMN(A:G)/(A1:G1<>""),{5,4,3,2,1})) copied down.
Aggregate creates an array of the column numbers divided by 1 or 0 (TRUE or FALSE). Divided by 0 results in an error and gets ignored. It then takes the 5th largest to the largest column number without error and returns that as an array on the indexed row.
Where 1:1 represents the first row and A:G represents the first to last column used.
If you would want it on row 2 and column A:Z you'd have to amend it like this:
=INDEX(2:2,AGGREGATE(14,6,COLUMN(A:Z)/(A2:Z2<>""),{5,4,3,2,1}))
Different approach - using the new Excel 365 formulas:
This will return the values of the last five non-empty cells of row 2
=LET(
data,FILTER(B2:H2,B2:H2<>""),
cntData,COUNT(data),
matrix,SEQUENCE(1,MIN(cntData,5),IF(cntData>5,cntData-4,1)),
INDEX(data,1,matrix)
)
data returns all values except empty cells using the FILTER- formula
cntData holds the number of cells
using SEQUENCE a matrix is build that will return the column-indices to be returned. In case less then 5 values are available, the matrix returns 1 to cntData.
finally this "index-matrix" is used to return the values from the filtered data
This could be enhanced, by storing the number of cells to be returned within a named cell - and referencing this name in the formula. By that you could easily alter the number without altering the formula.
A
B
C
D
4
1
6
5649
3
8
10
9853
5
2
7
1354
I have two worksheets, for example column A in sheet 1 and columns B-D in sheet 2.
What I want to do is to take one value in Column A, and scan both columns B and C and it is between those two values, then display the corresponding value from column D in a new worksheet.
There could be multiple matches for each of the cell in column A and if there is no match, to skip it and not have anything displayed. Is there a way to code this and somehow create a loop to do all of column A? I tried using this formula, but I think it only matches for each row and not how I want it to.
=IF(AND([PQ.xlsx]Sheet1!$A2>=[PQ.xlsx]Sheet2!$B2,[PQ.xlsx]Sheet1!$A2<[PQ.xlsx]Sheet2!$C2),[PQ.xlsx]Sheet2!$D$2,"")
How do I do this?
Thank you.
I'm not positive if I understood exactly what you intended. In this sheet, I have taken each value in A:A and checked to see if it was between any pair of values in B:C, and then returned each value from D:D where that is true. I did keep this all on a single tab for ease of demonstration, but you can easily change the references to match your own layout. I tested in Excel and then transferred to this Google Sheet, but the functions should work the same.
https://docs.google.com/spreadsheets/d/1-RR1UZC8-AVnRoj1h8JLbnXewmzyDQKuKU49Ef-1F1Y/edit#gid=0
=IFERROR(TRANSPOSE(FILTER($D$2:$D$15, ($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15))), "")
So what I have done is FILTEREDed column D on the two conditions that Ax is >= B:B and <= C:C, then TRANSPOSED the result so that it lays out horizontally instead of vertically, and finally wrapped it in an error trap to avoid #CALC where there are no results returned.
I added some random data to test with. Let me know if this is what you were looking at, or if I misunderstood your intent.
SUPPORT FOR EXCEL VERSIONS WITHOUT DYNAMIC ARRAY FUNCTIONS
You can duplicate this effect with array functions in pre-dynamic array versions of Excel. This is an array function, so it has be finished with SHFT+ENTER. Put it in F2, SHFT+ENTER, and then drag it to fill F2:O15:
=IFERROR(INDEX($D$2:$D$15, SMALL(IF(($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15), ROW($A$2:$A$15)-MIN(ROW($A$2:$A$15))+1), COLUMNS($F$2:F2))),"")
reformatted for easier explanation:
=IFERROR(
INDEX(
$D$2:$D$15,
SMALL(
IF(
($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15),
ROW($A$2:$A$15) - MIN(ROW($A$2:$A$15))+1
),
COLUMNS($F$2:F2)
)
),
"")
From the inside out: ROW($A$2:$A$15) creates an array from 2 to 15, and MIN(ROW($A$2:$A$15))+1 scales it so that no matter which row the range starts in it will return the numbers starting from 1, so ROW($A$2:$A$15) - MIN(ROW($A$2:$A$15))+1 returns an array from 1 to 14.
We use this as the second argument in the IF clause, what to return if TRUE. For the first argument, the logical conditions, we take the same two conditions from the original formula: ($A2>=$B$2:$B$15)*($A2<=$C$2:$C$15). As before, this returns an array of true/false values. So the output of the entire IF clause is an array that consists of the row numbers where the conditions are true or FALSE where the conditions aren't met.
Take that array and pass it to SMALL. SMALL takes an array and returns the kth smallest value from the array. You'll use COLUMNS($F$2:F2) to determine k. COLUMNS returns the number of columns in the range, and since the first cell in the range reference is fixed and the second cell is dynamic, the range will expand when you drag the formula. What this will do is give you the 1st, 2nd, ... kth row numbers that contain matches, since FALSE values aren't returned by SMALL (as a matter of fact they generate an error, which is why the whole formula is wrapped in IFERROR).
Finally, we pass the range with the numbers we want to return (D2:D15 in this case) to INDEX along with the row number we got from SMALL, and INDEX will return the value from that row.
So FILTER is a lot simpler to look at, but you can get it done in an older version. This will also work in Google Sheets, and I added a second tab there with this formula, but array formulas work a little different there. Instead of using SHFT+ENTER to indicate an array formula, Sheets just wraps the formula in ARRAY_FORMULA(). Other than that, the two formulas are the same.
Since FALSE values aren't considered, it will skip those.
I have a range that I want to sum, which is A2:M35. However, if column 'N' has the number 1 in it, I want to exclude that entire row from the sum. So, If N3 contains 1 I want to exclude the range A3:M3 from the sum calculation. Is this possible?
UPDATE:
I should also include that the 1 or 0 in column N is a flag to state whether this row should be excluded or not (1 = yes, 0 = no). However, this value is derived by checking whether any values in that row = "excluded". So, the additional complication here appears to be that even though the rows with "excluded" in them should be excluded, the sum calculation will show '#VALUE' as it believes some of the values are of the wrong data type (even though they shouldn't be included).
SIMPLE SOLUTION (with helper column)
If you can, to keep it simple, I'd just add a helper column.
So In cell O2:
=IF($N2=1,0,SUM($A2:$M2))
Drag that down to cell O35.
Then you can simply:
=SUM($O$2:$O$35)
COMPLEX SOLUTION (no helper column)
If you would like to avoid having to have a helper column cluttering up your sheet, you could use a SUMPRODUCT formula:
=SUMPRODUCT($A$2:$M$35,(LEN($A$2:$M$35)-LEN($A$2:$M$35))+NOT($N$2:$N$35))
HOW IT WORKS:
The first range (A2:M35) is the array (or in this case a range of excel cells) that you want to sum.
The SUMPRODUCT is going to take each value in that array and multiply it by each corresponding value in the next array we supply, then sum all the results together.
The problem is that the first array is a table, 13 values across and 34 values down. The second array (column N) is only 1 value across. SUMPRODUCT requires that all arrays are the same size.
To do this, we first create an array the correct size:
(LEN(A2:M35)-LEN(A2:M35))
LEN returns an array containing the number of characters in each cell supplied to it. If we take it away from it's self, we are left with an array of the correct size, filled with zeros.
We can then add the values in our smaller array (column N) to the zeros in the array of the correct size, this will fill all the columns with the correct value.
+NOT(N2:N35))
The NOT is there because we want to sum the rows which have a zero. All it is doing is swapping the zeros and ones in column N. So, all 1's become 0's and vice versa.
I hope you can follow my explanation. If not, please let me know and I will elaborate.
Suppose the following series:
I am trying to find the latest non 1 value that precedes the latest 1.
In this case it should return 3 and not 4.
1 being the minimum value I have tried to use MATCH(MIN(range),range,0) and add 1 to get the value I needed, but the minimum function gets stuck on the first occurrence of the minimum.
Try
=INDEX(B1:P1,1,MATCH(1,(OFFSET(B1:P1,,-1)=1)*(B1:P1>1),0))
Where B1:P1 is your data range. Of course it is an array formula (SHIFT+ENTER).
Hope that helps.
I can't see a short and snappy answer to this but here is one suggestion assuming the data starts in column A
=INDEX(2:2,AGGREGATE(15,6,COLUMN(INDEX(2:2,MATCH(1,2:2,0)):INDEX(2:2,MATCH(999,2:2)))/(INDEX(2:2,MATCH(1,2:2,0)):INDEX(2:2,MATCH(999,2:2))>1),1))
If the range didn't start in column A, you would have to subtract the number of the column before the first column of the range from the column number returned by the AGGREGATE to get the correct index value relative to the start of the array e.g. for B2:Z2
=INDEX(B2:Z2,AGGREGATE(15,6,COLUMN(INDEX(B2:Z2,MATCH(1,B2:Z2,0)):INDEX(B2:Z2,MATCH(999,B2:Z2)))/(INDEX(B2:Z2,MATCH(1,B2:Z2,0)):INDEX(B2:Z2,MATCH(999,B2:Z2))>1),1)-COLUMN(A:A))
To be honest it wouldn't be worth using a MATCH to find the last number in the range unless the number of cells in the range was very large, so the formula for B2:Z2 would just be
=INDEX(B2:Z2,AGGREGATE(15,6,COLUMN(INDEX(B2:Z2,MATCH(1,B2:Z2,0)):Z2)/(INDEX(B2:Z2,MATCH(1,B2:Z2,0)):Z2>1),1)-COLUMN(A:A))
Formula starting column A
Formula starting at column B
I'm learning to use array formulas and have been successful doing simple things like adding 2 columns together in a third column. For example, I can put =arrayformula(B:B+C:C) in D1 and it adds B and C for each row.
But now I have a situation where I want to subtract two numbers in the same column. I want to take the value of that column in the current row and subtract the previous row's value from it. Without array formulas this is simple: in O7 I put =N7-N6 and cop that down so O8 gets =N8-N7, etc. But that requires copying down every time - can I do the same thing with an array formula?
Basically, can I do something like =arrayformula(B:B+(B-1):(B-1)) ?
Context: column N is a monthly account balance. I would like to calculate how much that balanced changed each month. So for row 7, =N7-N6 gives me that difference. But I'm changing the entire spreadsheet to array formulas so I can stop pasting all of the formulas and I'm stuck on this one since it's comparing the same column.
I'm trying to get everything into Row 1 so my values and calculations can start in Row 2. For example, here's one of my formulas in Row 1:
arrayformula(if(row(A:A)=1,"Total gross income",if(LEN(B:B),B:B+C:C,"")))
Unfortunately, in Column O (the one I asked about originally) if I do this:
=arrayformula(if(row(A:A)=1,"Amount saved this month",if(row(A:A)>1,if(LEN(N:N),N2:N-N:N,""))))
Or this:
=arrayformula(if(row(A:A)=1,"Amount saved this month",if(row(A:A)>1,if(LEN(N:N),offset(N:N,1,0)-N:N,""))))
Every row is off by 1 - the result that should go in Row 3 goes in Row 2, etc. And if I do this:
=arrayformula(if(row(A:A)=1,"Amount saved this month",if(row(A:A)>1,if(LEN(N:N),N:N-offset(N:N,-1,0),""))))
Then it gives me an error because the offset function is trying to evaluate something out of range (possibly it starts with N1 and tries to grab a value 1 row above N1?)
Any advice on how to handle that out-of-range error?
I think the error is because of offset range N:N which starts from N1 and you are trying to shift it -1 or one cell up, which brings the formula out of sheet.
Try this formula instead:
=arrayformula(
{"Amount saved this month";
if(LEN(N2:N),N2:N-offset(N2:N,-1,0),"")})
It uses {} to make an array. See more info:
https://support.google.com/docs/answer/6208276?hl=en
Bonus. There is no reason to check row number now.