I have a table in excel with two columns [RunningTotal] and [Change].
I have a formula like this for [RunningTotal]
=IFERROR(OFFSET([#RunningTotal];-1;0);100)+[#Change]
Its a table with two columns, one for a running total and the other for the change. The IFERROR is for the first row since it cannot be offset because there are no rows before it.
My table looks like this.
3 , #VALUE!
4 , 104
2 , 106
5 , 111
etc...
First row throws a error, the second row to reference the first row produce an error but then fallback's to the value 100 + change.
Have i done something wrong?
In fact, you are accessing the cell one above the top of the tables's data body. It is the header string value (e.g. RunningTotal) and you receive the #VALUE! error when you try to use the string mathematically with the #Change number.
However, the SUM of a string is zero so that could be checked for.
=IF(SUM(OFFSET([#RunningTotal], -1, -1, 1, 2)), OFFSET([#RunningTotal], -1, 0), 100)+[#Change]
That formula checks that the row being examined will SUM to zero for both #Change and #RunningTotal.
After rereading your original formula it has occurred to me that you could also use your original if you brought the +[#Change] into the error evaluation.
=IFERROR(OFFSET([#RunningTotal], -1, 0)+[#Change], 100+[#Change])
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.
I have included 2 tables below to illustrate my problem.
Table 1
Table 2
I am trying to find a formula that fills rows 140, 143 & 146 (Table 2) from rows 15,16 & 17 (Table 1). There is over 100 so it is quite time consuming to input =B15 etc over and over again.
The offset method e.g. =OFFSET($B$15,(ROW()-1)*3,0) only works when I'm referencing gaps, not trying to fill them.
Essentially, where B140's formula is =B15, B143's will be =B140 + 1 row i.e. B16
Thanks for your help!
If you are trying find value for appropriate month you can use INDEX/MATCH entered as array formula:
=IFERROR(INDEX($B$1:$B$4,MATCH(TRUE,MONTH(A10)=MONTH($A$1:$A$4),0)),"")
Array formula after editing is confirmed by pressing ctrl + shift + enter
Edit
To find by month & year use:
=IFERROR(INDEX($B$1:$B$4,MATCH(1,(MONTH(A10)=MONTH($A$1:$A$4))*(YEAR(A10)=YEAR($A$1:$A$4)),0)),"")
it's also array formula
You can use modulo for this. With the Modulo function, you check if the remainder of the row you're on is divisible by a number (e.g. 3 if you want to copy a value every third row). IF(MOD(ROW(E1);3 = 0)
If that's the case, you can divide by 3 and use for example the Index function to copy the nth value of another location (or another worksheet). If that's not the case, you print "" to get an empty row.
=IF(MOD(ROW(E1);3)=0;INDEX($B$1:$B$4;ROW(E1)/3);"")
If you're working with offsets because the row numbers are not on numbers divisible by three, you could manually offset the rows (and do the same for the division that yields the index row). For example, if you want to have rows 2, 5, 8 etc:
=IF(MOD(ROW(E1)+1;3)=0;INDEX($B$1:$B$4;ROW(E2)+1/3);"")
I am trying to run a formula that does the following:
I have three columns, an account number, recorded amount, and the actual amount. What I'm trying to do is this, if the actual amount is not equal to the recorded amount, I want to pull that line, including the account number, recorded amount, and actual amount, and put it into a separate sheet. I'm trying to get this to happen over the span of about 100 rows. So it would look like this:
Account | Recorded Amount | Actual Amount
-----------------------------------------
Company | $356 | $356
Company | $569 | $569
Company | $700 | $705 ** Doesn't match
Company | $300 | $320 ** Doesn't match
##Now since the third and fourth rows don't match their respective columns
##The data is then extracted into a separate sheet.
**Separate Spreadsheet**
Account | Recorded Amount | Actual Amount
-----------------------------------------
Company | $700 | $705
Company | $300 | $320
I've tried using Vlookup and Match functions, but can't seem to figure this one out. Any help would be appreciated!
Attempts:
Attempting to use IF statement, the problem I encounter is not being able to return the whole row. I can return a specific cell but not the entire row.
=IF(E5=D5,A5:E5,"") * give a #VALUE error
=IF(E5=D5,E5) * returns selected cell
=VLOOKUP(E15=D15,D15:E299,2,FALSE) * #N/A
Tried using it across a sequence, but it'll only return the first cell that is selected, in this case, it would just return 'Company'. I could run this for each row but that's a lot of effort and code to run that piece of code across multiple columns and rows. It's also not scalable.
The main problem I'm having is capturing the entire row. I can extract the value of a specific cell if it matches, but not the entire row of data. I would also accept that Excel is not capable of this. I was able to generate the required results in a couple of lines of code in Python but in Excel, I'm not as fluent and I'm unsure of what path to take.
Suggested solution
If I understand you correctly, the solution could be the following.
Sheet1 contains the source data:
Sheet2 contains a table with calculated data: only those rows that differ in the values Recorded and Actual:
Cells A2:C9 of Sheet2 contain formulas. This is the same range of cells like the source data on Sheet1. Sheet2 A2 contains this formula:
{=IFERROR(INDEX('Sheet1'!$A$2:$C$9,LARGE(N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9)*(ROW('Sheet1'!$B$2:$B$9)-ROW('Sheet1'!$B$1)),SUM(N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9))-ROWS(A$1:A1)+1),COLUMNS($A1:A1)),"")}
The formula is copied to the other cells up to C9. You may adjust cell references to your needs.
Note that this is an array formula. Omit the curly braces and enter the formula by pressing Ctrl + Shift + Enter.
Explanation
I will try my best...
Let's start with a slightly better readable formula.
{=IFERROR(
INDEX(
'Sheet1'!$A$2:$C$9,
LARGE(
N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9) * (ROW('Sheet1'!$B$2:$B$9)-ROW('Sheet1'!$B$1)),
SUM(N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9)) - ROWS(A$1:A1) + 1
),
COLUMNS($A1:A1)
),
""
)}
Main definitions
INDEX
Returns the value of an element in a table or an array, selected by the row and column number indexes.
Usage is INDEX(array, rowNumber, columnNumber).
Example: if D6 contains Hello World! then INDEX(C3:E20, 4, 2) returns Hello World! (2nd cell in 4th row in the given range)
LARGE
Returns the k-th largest value in a data set. You can use this function to select a value based on its relative standing. For example, you can use LARGE to return the highest, runner-up, or third-place score.
Usage is LARGE(array, k).
Example: LARGE({1,5,5,9,2,7,0,1}, 2) = 7 (7 is the second largest value)
Breakdown of the formula
1) Find row numbers
It all starts with a comparison of the columns B and C.
'Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9
Remind that this is an array formula. Thus the result of this comparison is an array containing boolean values.
{FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE}
In the next step the boolean-array is multiplied with the relative row numbers. ROW('Sheet1'!$B$2:$B$9) returns the absolute row numbers: {2,3,4,5,6,7,8,9}. The position of the heading ROW('Sheet1'!$B$1) is subtracted. We get the relative row numbers {1,2,3,4,5,6,7,8}.
Both arrays are multiplied.
N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9) * (ROW('Sheet1'!$B$2:$B$9) - ROW('Sheet1'!$B$1))
Replaced with values:
N({FALSE,TRUE,FALSE,FALSE,TRUE,TRUE,FALSE,TRUE}) * ({2,3,4,5,6,7,8,9} - 1)
Resolved:
{0,1,0,0,1,1,0,1} * {1,2,3,4,5,6,7,8,9}
The resulting array contains the relative row numbers of those rows that differ in B and C.
{0,2,0,0,5,6,0,8}
2) Arrange row numbers in desired order
The result of the LARGE function is passed as row number parameter to the INDEX function. We want the INDEX function to return errors (discussed later) for rows with equal values in columns B and C. Thus we have to implement some weird logic to calculate the k parameter for the LARGE function.
LARGE(
N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9) * (ROW('Sheet1'!$B$2:$B$9)-ROW('Sheet1'!$B$1)),
SUM(N('Sheet1'!$B$2:$B$9<>'Sheet1'!$C$2:$C$9)) - ROWS(A$1:A1) + 1
),
The SUM counts rows having differences in columns B and C =4, then the currently viewed row ROWS(A$1:A1) is subtracted and 1 is added. We get following values for the k parameter of LARGE: 4, 3, 2, 1, 0, -1, -2, -3.
LARGE({0,2,0,0,5,6,0,8}, k)
The resulting values are:
2, 5, 6, 9, #NUM!, #NUM!, #NUM!, #NUM!
3) Pick the values
The INDEX function references the source data 'Sheet1'!$A$2:$C$9. Row numbers are the values we just calculated with LARGE, and column number is the currently viewed column COLUMNS($A1:A1).
For the first target row INDEX returns the values of the second source row, for the second target row the values of the 5th source row, and so on. From the 5th target row onwards we don't want to display anything. If we would use 2, 5, 6, 9, 0, 0, 0, 0 for the row numbers INDEX would write unwanted values in the 5th to 8th line. This is why we wanted LARGE to return #NUM! for rows with equal values. If INDEX is passed #NUM! then it also returns #NUM!. Finally, we can handle these cases with IFERROR(..., "") and get empty cells.
That's it.
I have two different sheets with 300,000 data in Excel.
First sheet contains:
S2_Symbol Start_Pos End Position
STE 254857 267891
PRI 748578 758962
ILA 852741 963369
VIS 789456 796325
Second:
S1_Location
789460
852898
748678
My output should be like this:
S1_Location Symbol
789460 VIS
852898 ILA
748678 PRI
I have to find that S1_location falls in which S2_location and its corresponding Symbol. I have used INDEX formula in Excel but for each cell, I have to change the reference cell manually. I couldn't do it 300,000 data.
How can I do in an in Excel or should I use a script?
This solution assumes the following:
Start and End Positions for each S2 Symbol are unique (i.e. there is no intersection between the ranges allocated to each symbol)
Data in first sheet is located at A1:D17 (adjust ranges in formulas as needed)
Data in second sheet is locate at A1:B300010 (adjust ranges in formulas as needed)
The solution requires:
To add a working column in worksheet one. Enter this formula in D2 and copy till last record.
=ROWS($A$1:$A2)
Fig. 1
Then in second worksheet enter this formula at B2 and copy till last record.
=INDEX( Sheet1!$A$1:$A$17,
SUMIFS( Sheet1!$D$1:$D$17,
Sheet1!$B$1:$B$17, "<=" & $A2, Sheet1!$C$1:$C$17, ">=" & $A2 ) )
Fig. 2
It took aprox. less than 14 seconds to copy downwards and calculate the formulas in sheet 2.
As it can be seen in figures 1 and 2 none of the tables need to be sorted.
Assuming both sheets start in A1, and First sheet ColumnB is sorted ascending, in Second sheet B2 please try:
=INDEX(First!A:A,MATCH(A2,First!B:B))
copied down to suit. It relies on inexact matching.
Assuming we have a Sheet1 like this:
note, the Sheet1is sorted by Start_Pos, End_Pos in ascending order.
and a Sheet2 like this:
Then the formula in Sheet2!B2 downwards could be:
=INDEX(Sheet1!A:A,IF(MATCH(A2,Sheet1!B:B)>IFERROR(MATCH(A2-(10^-10),Sheet1!C:C),0),MATCH(A2,Sheet1!B:B),NA()))
See MATCH: https://support.office.com/en-us/article/MATCH-function-e8dffd45-c762-47d6-bf89-533f4a37673a
The idea is: MATCH without exact matching (without parameter match_type) gets the row of the largest value which is smaller or equal the search value. So in the Start_Pos column it will get the row from which we can get the S2_Symbol. But from the End_Pos column it should get one row beforehand if the value is not outside the given ranges.
There is only one exception. If the value is exact the value in the End_Pos column, then it will return the same row as in the Start_Pos column. Considering this exception, we can search in the End_Pos column with a little bit smaller value. Thanks to Tom Sharpe for his comment.
The formula in Sheet2!D2 downwards is:
{=INDEX(Sheet1!A:A,MIN(IF($A2>=Sheet1!$B$2:$B$300000,IF($A2<=Sheet1!$C$2:$C$300000,ROW(Sheet1!$A$2:$A$300000),2^20+1))))}
this is an array formula which is exactly formulated respecting the requirements. But this is very bad in performance for using in much many cells. But using this, the Sheet1 is not required to be sorted.
Benchmark test:
Have the following Sheet1:
Formulas:
A2:A300002: ="S"&(ROW(A1)-1)*10&"-"&(ROW(A1)-1)*10+7
B2:B300002: =(ROW(A1)-1)*10
C2:C300002: =B2+7
and the following Sheet2:
Formulas:
A2:A300002: =RANDBETWEEN(0,3000007)
B2:B300002: =INDEX(Sheet1!A:A,IF(MATCH(A2,Sheet1!B:B)>IFERROR(MATCH(A2-10^-9,Sheet1!C:C),0),MATCH(A2,Sheet1!B:B),NA()))
Note the -10^-9 instead of -10^-10 in previous version. This is because we have only 16 digits precision. In previous version this was maximum 6 digits integer part and then 10 digits decimal part. Now it is maximum 7 digits integer part and then 9 digits decimal part.
Calculation after pressing F9 in Sheet2 takes ca. 2 s. (Excel 2007, Windows 7, 4 core processor).
I would have gone for something like this which gives you the first match if there is one:-
=INDEX(First!A:A,MATCH(1,(First!B:B<=A2)*(First!C:C>=A2),0))
assuming keys and start and end values are in a sheet called First and lookup values start in A2.
Array formula which must be entered with CtrlShiftEnter
In response to the question from #pnuts about how long it will take, I have set up a similar benchmark with 300,000 rows in each sheet and it has reached 1% after 90 minutes, so it should take about 150 hours to reach 100% or roughly one week. This is to be expected as the number of computations required is (rows in sheet 1) X (rows in sheet 2)
300,000 X 300,000
but in fact because the multiplication applies to complete columns, I believe it is more correctly
300,000 X 1,048,576
i.e. > 300 billion.
A practical version which gives good response for smaller ranges is as follows:-
I define three named ranges Range1, Range2 and Range3
=First!$A$1:INDEX(First!$A:$A,MATCH("ZZZ",First!$A:$A))
=First!$B$1:INDEX(First!$B:$B,MATCH(9.9E+307,First!$B:$B))
=First!$C$1:INDEX(First!$C:$C,MATCH(9.9E+307,First!$C:$C))
and the modified formula is
=INDEX(Range1,MATCH(1,(Range2<=A2)*(Range3>=A2),0))
I was thinking of deleting this answer, but would rather it stood as a counter-example.
I have 2 Excel files and I'm trying to compare two numbers (one has 7 digits and the second 5 digits).
For example in an excel file I have the following number 1234567 and in another file I have 12345 in one cell in another cell I have the remaining digits 67. I want to compare the first number with the second and if they are the same i need to identify the cells that have the value 67 and to print what is in the next cell.
They are constantly changing so I'm having problems getting this right
I made this formula but it doesn't work properly. Did I miss something?
=IFERROR(IF(INT(RIGHT(A5;2))=VLOOKUP(INT(LEFT(A5;5));'Path[file.xls]
Sheet1'!$S$3:$AA$200;2;FALSE);VLOOKUP(INT(LEFT(A5;5));'path[file.xls]
Sheet1'!$S$3:$AA$200;3;FALSE);VLOOKUP(INT(LEFT(A5;5));'path[file.xls]
Sheet1'!$S$3:$AA$200;5;FALSE));"")
From your description and sample formula, I pieced together some sample data in File.xls.
Note by the right alignment, these are true numbers. This is important. A VLOOKUP or MATCH function will not find RIGHT(A2, 5) amongst numbers; it has to be --RIGHT(A2, 5). With 7 digit numbers in another workbook, I used this standard formula.
=INDEX([File.xls]Sheet1!$S:$AA, MATCH(--LEFT(A2, 5), [File.xls]Sheet1!$S:$S, 0), MATCH(--RIGHT(A2, 2), INDEX([File.xls]Sheet1!$S:$AA, MATCH(--LEFT(A2, 5), [File.xls]Sheet1!$S:$S, 0), ), 0)+1)
Note that every values is expected to be found. If this is not the case, then an IFERROR function should be used to handle non-matches.
The results were as follows.