Merge two columns into one column, one cell after another - excel

I am trying to merge two columns into one column, one cell after another. For example, I have start time in one column and End time into another column, shown in pic. I am trying to merge them into one column (Time) that has start time in one cell and end time in the cell just below it, with duplicating the code (the third column) with each addition. Like shown in the pic.
Is there a way to do that?

Forwards:
Formula in D2:
=INDEX($A$2:$B$9,ROUND(ROW(A1)/2,0),MOD(ROW(),2)+1)
Formula in E2:
=INDEX($C$2:$C$9,ROUND(ROW(A1)/2,0))
Backwards:
Formula in D2:
=INDEX($A$2:$B$9,ROUND(((COUNTA(C:C)-1)*2-(ROW(A1)-1))/2,0),MOD(ROW(A1),2)+1)
Formula in E2:
=INDEX($C$2:$C$9,ROUND(((COUNTA(C:C)-1)*2-(ROW(A1)-1))/2,0))

This is the forumula I would use:
=CHOOSE(SEQUENCE(,2),INDEX(A1:B8,(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0)-MOD(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0),COLUMNS(A1:B8)))/COLUMNS(A1:B8)+1,MOD(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0),COLUMNS(A1:B8))+1),INDEX(C1:C8,(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0)-MOD(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0),COLUMNS(A1:B8)))/COLUMNS(A1:B8)+1))
But that formula is a bit messy, so, I wrote another one that breaks down the formula in a way that I can talk through how it works and what its doing:
=LET(
TimeRange,A1:B8,
CodeRange,C1:C8,
RowCount,ROWS(TimeRange),
ColumnCount,COLUMNS(TimeRange),
CellCount,RowCount*ColumnCount,
BaseSequence,SEQUENCE(CellCount,,0),
ModSequence,MOD(BaseSequence,ColumnCount),
RowIndex,(BaseSequence-ModSequence)/ColumnCount+1,
ColumnIndex,ModSequence+1,
Result1,
INDEX(TimeRange,RowIndex,ColumnIndex),
Result2,
INDEX(CodeRange,RowIndex),
CHOOSE(SEQUENCE(,2),Result1,Result2)
)
If you want to paste this formula into your spreadsheet, just make sure that you have the formula bar selected. If you don't, Excel will paste the text so that each line break moves to the next row.
What does each part do? This table steps through each parameter, and explains what each one does. And yes, when using a LET statement, you can use variable names declared in the prior step, but you can't do it the other way!
Part
Explanation
LET(
LET basically allows us to name our own variables. You'll see what I mean in the following sections
TimeRange, B11#
This is the StartTime and EndTime Ranges from your example
CodeRange, D11#
This is the Code range from your example
RowCount, ROWS(TimeRange)
This gives us the number of rows in TimeRange, and stores it as RowCount
ColumnCount, COLUMNS(TimeRange)
This gives us the number of columns in TimeRange, and stores it as RowCount
CellCount, RowCount*ColumnCount
This calculates how many cells there are. Note that our answer will have rows equal to CellCount
BaseSequence, SEQUENCE(CellCount,,0)
This creates a sequence of numbers, arranged in a single column, starting at 0, and stores the result in BaseSequence
ModSequence, MOD(BaseSequence, ColumnCount)
Here, we take the MOD of BaseSequence, by ColumnCount. Why? Because this effectively gives us a list of numbers counting up from 0 to 1. Note that this is why BaseSequence had to start at 0
RowIndex, (BaseSequence - ModSequence)/ColumnCount + 1
This basically counts through the rows, giving us 1, 1, 2, 2, 3, 3, (etc)
ColumnIndex, ModSequence + 1
Because unlike MOD, which starts at 0, column and row indices start at 1
Result1, INDEX(TimeRange, RowIndex, ColumnIndex)
This is our left hand column, and basically picks through the TimeRange, going through each row by picking up each column first
Result2, INDEX(CodeRange, RowIndex)
This is our right hand column, and it basically doubles up each element in the CodeRange (i.e. teacher, teacher, student, etc), because RowIndex runs 1, 1, 2, 2, 3…
CHOOSE(SEQUENCE(,2),Result1, Result2)
The last item in a LET statement is the one that returns a value to the spreadsheet. Here, I'm using a SEQUENCE to make a range 1 row and ColumnCount columns wide (i.e. [1, 2]). This goes into CHOOSE, which will select Result1 when it gets a 1, and Result2 when it gets a 2. Because both Result1 and Result2 are ranges, CHOOSE effectively combines them into a single Range
Also, in the event you want it, this is the formula I posted first (at the top), but with additional line breaks to improve legibility:
=CHOOSE(
SEQUENCE(,2),
INDEX(
A1:B8,
(
SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0)
-MOD(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0),COLUMNS(A1:B8))
)
/COLUMNS(A1:B8)+1,
MOD(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0),COLUMNS(A1:B8))+1
),
INDEX(
C1:C8,
(
SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0)
-MOD(SEQUENCE(ROWS(A1:B8)*COLUMNS(A1:B8),,0),COLUMNS(A1:B8))
)
/COLUMNS(A1:B8)+1
)
)

Assuming your data starts in row 2.
=A2&" "&B2

Related

How to make Excel follow a formula algorithm on every 3 rows

I want to make Excel follow a formula pattern on every 3 rows, such that after an increase of three in the conditional if statement, there should be an increment of one on return value "TRUE". So that every time I drag it down, the algorithm gets applied to succeeding 3 rows that it follows. I have this simple formula of:
=IF(B11="RTR",RTR!G11:Z11,IF(B11="DHG2",'DHG2'!G11:Z11,IF(B11="JQV",JQV!G11:Z11,"")))
=IF(B12="RTR",RTR!G11:Z11,IF(B12="DHG2",'DHG2'!G11:Z11,IF(B12="JQV",JQV!G11:Z11,"")))
=IF(B13="RTR",RTR!G11:Z11,IF(B13="DHG2",'DHG2'!G11:Z11,IF(B13="JQV",JQV!G11:Z11,"")))
=IF(B14="RTR",RTR!G12:Z12,IF(B14="DHG2",'DHG2'!G12:Z12,IF(B14="JQV",JQV!G12:Z12,"")))
=IF(B15="RTR",RTR!G12:Z12,IF(B15="DHG2",'DHG2'!G12:Z12,IF(B15="JQV",JQV!G12:Z12,"")))
=IF(B16="RTR",RTR!G12:Z12,IF(B16="DHG2",'DHG2'!G12:Z12,IF(B16="JQV",JQV!G12:Z12,"")))
Following the formula I wanted, it's supposed to be followed by:
=IF(B17="RTR",RTR!G13:Z13,IF(B17="DHG2",'DHG2'!G13:Z13,IF(B17="JQV",JQV!G13:Z13,"")))
I tried dragging down the formula to apply it to below rows but the pattern doesn't follow to what I wanted. Instead, the row below goes into like:
=IF(B17="RTR",RTR!G17:Z17,IF(B17="DHG2",'DHG2'!G17:Z17,IF(B17="JQV",JQV!G17:Z17,"")))
Need a little bit of help here.
Thank you.
Here is a solution that doesn't require helper cells:
This formula will increment by 1 every 3 rows:
=CEILING.MATH(ROW()/3)
If you want the sequence to start on a different row, say row 10, you can just subtract that number - 1 from the ROW(), so for starting on row 10 from 1, subtract 9:
=CEILING.MATH((ROW()-9)/3)
And if you wanted the sequence to start from a different number at a different row, you can just add that number -1 to this whole thing, this example will start at 11 on row 10:
=CEILING.MATH((ROW()-9)/3)+10
EDIT: Much better solution proposed by P.b, you don't need the IFs at all:
=INDIRECT(B11 & "!G" & (CEILING.MATH(ROW()/3)+10) & ":Z" & (CEILING.MATH(ROW()/3)+10))
So, an example which you can expand:
VLOOKUP(A1,INDIRECT("'RTR'!"&"G11:Z11",1),1,0)
Not sure where you increment of 3 occurs as B11 goes to B12 and even the last two B16 goes to B17 and the target range matches the row numbers.
As I have shown you can build the target range so adding the row numbers is trivial now. They can be taken from cells, C1 could be 3, C2 6 etc.
The following could be used (to avoid using (volatile) INDIRECT):
=INDEX(
CHOOSE( MATCH(B11, {"RTR","DHG2","JQV"}, 0),
'RTR'!G:Z, 'DHG2'!G:Z, 'JQV'!G:Z),
INT((ROW()-11)/3)+11,
)
It selects the correct tab by matching the value in B11 to an array mentioning the names of the tabs. It than indexes range G:Z from that tab.
The row number shifts 1 number every 3 rows because of INT((ROW()-11)/3)+11.

Is there a way to scan an entire column based on one cell in another column and pull out a value of the corresponding column?

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.

Is there a way to automatically extract a row into another spreadsheet if the cell matches its counter cell in excel?

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.

Is there a 2 Value Look up function in MS Excel that can perform the following?

I am going crazy over this. It seems so simple yet I can't figure this out. I have two worksheets. First worksheet is my data. Second is like an answer key. Upon checking checking, A1:B1 in Sheet 1 is a match with the conditions in Row 52 in SHEET 2, therefore, the value in Column C is "MGC". What is the formula that will perform this function? It's really hard to explain without the data so I pasted a link of the sample spreadsheet. Thank you so much in advance.
sample spreadsheet here. https://docs.google.com/spreadsheets/d/1_AjuNfCdGfEM-XkqPa6W4hSIxQg4NM2Vg4c2C1pQ_vQ/edit?usp=sharing
screenshot here. (wont let me post i have no reputation)
In Sheet2, insert a column in front of Column A and put the formula in A2 =C2&D2.
Then in Sheet1, Cell C2 the formula =vlookup(A2&B2,Sheet2!A:B,2,0).
the first make a concatenated key to lookup, then the second looks up that key.
How about a index(match())? If I've understood correctly you need to match across both the A and B column in sheet one, checking for the relevant values in B and C on sheet 2 to retrun worksheet 2 column a to worksheet 1 column c.
third version try:
=INDEX(Sheet2!$C$1:$C$360,MATCH(Sheet1!A1&Sheet1!B1,Sheet2!$B$1:$B$360&Sheet2!$C$1:$C$360,0))
Basically what this does is use concatenation, the & operator, to specify you are looking for "Criteria A" & "Criteria B" in sheet 1, which makes the string "Criteria A Criteria B", which is supplied in the first part of the match function.
In the second it then says match this against all of my variables in sheet 2 in the same way with concantenation.
The final part of match function (0) specifies you want an 'exact' match
It then supplied this as a reference to the index function, which then finds the row intersecting with the value you want, and returns that.
As noted here https://support.microsoft.com/en-us/kb/59482 this is an array formula, so it behaves differently, and must be input differently. https://support.office.com/en-za/article/Guidelines-and-examples-of-array-formulas-7d94a64e-3ff3-4686-9372-ecfd5caa57c7
There are (at least) 2 ways you could do this without VBA.
USING A SORTED LIST
The first relies on the assumption that your data can be re-sorted, so that everything "Unreported" is in the top, and everything "reported" is together below that (or vice versa). Assuming that this is the case (and it appears to already be sorted like this),we will use the function OFFSET to create a new range which shows only the values that align with either being "Unreported" or "Reported".
Offset takes a given reference to a point on a sheet, and then moves down/up & left/right to see what reference you want to return. Then, it returns a range of cells of a given height, and a given width. Here, we will want to start on Sheet2 at the top left, moving down until we find the term "Unreported" or "Reported". Once that term is found, we will want to move one column to the right (to pull column B from sheet 2), and then have a 'height' of as many rows as there are "unreported" or "reported" cells. This will look as follows in A1 on sheet 1, copied down:
=OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),1)
This says: First, start at cell A1 on sheet2. Then find the term in A1 (either "unreported" or "reported", on sheet2!A:A (we subtract 1 because OFFSET starts at A1 - so if your data starts at A1 we need to actually stay at "0". If you have headers on sheet2, you will not need this -1). Then, move 1 column to the right. Go down the rows for as many times as Sheet2 column A has the term found in Sheet1 A1. Stay 1 column wide. Together, this will leave you with a single range on sheet2, showing column B for the entire length that column A matches your term in sheet1 A1.
Now we need to take that OFFSET, and use it to find out when the term in Sheet1 B1 is matched in Sheet2 column B. This will work as follows:
=MATCH(B1,[FORMULA ABOVE],0)
This shows the number of rows down, starting at the special OFFSET array created above, that the term from B1 is matched in column B from sheet2. To use this information to pull the result from column C on sheet 2, we can use the INDEX function, like so:
=INDEX([FORMULA ABOVE],MATCH(B1,[FORMULA ABOVE],0))
Because this would be fairly convoluted to have in a single cell, we can simplify this by using VLOOKUP, which will only require the OFFSET function to be entered a single time. This will work as follows:
=VLOOKUP(B1,[FORMULA ABOVE],2,0)
This takes the OFFSET formula above, finds the matching term in B1, and moves to the 2nd column to get the value from column C in sheet2. Because we are going to use VLOOKUP, the offset formula above will need to be adjusted to provide 2 columns of data instead of 1. Together, this will look as follows:
FINAL FORMULA FOR SHEET1, C1 & COPIED DOWN
=VLOOKUP(B1,OFFSET(Sheet2!$A$1,MATCH(A1,Sheet2!A:A,0)-1,1,COUNTIF(Sheet2!A:A,A1),2),2,0)
OPTION USING ARRAY FORMULAS
The above method will only work if your data is sorted so that the REPORTED and UNREPORTED rows are grouped together. If they cannot be sorted, you can use an ARRAY FORMULA, which essentially takes a formula which would normal apply to a single cell, and runs it over an entire range of cells. It returns an array of results, which must be reduced down to a single value. A basic array formula looks like this [assume for this example that A1 = 1, A2 = 2...A5 = 5]:
=IF(A1:A5>3,A1:A5,"")
Confirm this (and all array functions) by pressing CTRL + SHIFT + ENTER, instead of just ENTER. This looks at each cell from A1:A5, and if the value is bigger than 3, it gives the number from that cell - otherwise, it returns "". In this case, the result would be the array {"";"";"";4;5}. To get the single total of 9, wrap that in a SUM function:
=SUM(IF(A1:A5>3,A1:A5,""))
In your case, we will want to use an array formula to see what row in Sheet2 matches A1 from Sheet1, and B1 from Sheet1. This will look like this:
=IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW($B$1:$B$100),""),"")
This checks which rows in column A from sheet 2 match A1. For those that do, it then checks which rows in column B from sheet 2 match B1. For those, it pulls the row number from that match. Everything else returns "". Assuming no duplicates, there should only 1 row number which gets returned. To pull that number from the array of results, wrap the whole thing in a MATCH function. Now that you have the row number, you can use an INDEX function to pull the result in Column C with that row, like this:
FINAL ARRAY FORMULA METHOD
=INDEX($C$1:$C$100,MAX(IF(Sheet2!$A$1:A$100=A1,IF(Sheet2!$B$1:$B$100,ROW(Sheet2!$B$1:$B$100),""),"")))
Remember to confirm with CTRL + SHIFT + ENTER instead of just ENTER, when you type this formula. Note that I didn't refer to all of Sheet2!A:A, because array formulas run very slowly over large ranges.
The following formula should work without making any changes to the datasheets.
=INDEX(Sheet2!$A$1:$A$360,MATCH(Sheet1!A1,IF(Sheet2!$C$1:$C$360=Sheet1!B1,Sheet2!$B$1:$B$360),0))
Remember to save this formula as an array with CTRL+SHIFT+ENTER
Documentation on how to use INDEX and MATCH against multiple criteria can be found on Microsoft Support.
It's not clear what you want to do with the multiples that do not have corresponding matches. txed is listed as Unreported twice in Sheet1; kntyctap is listed as Unreported three times. There are only one corresponding match on Sheet2 for each of these.
Non-array Standard Formulas for multiple criteria matches
For Excel 2010 and above use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999,AGGREGATE(15,6,ROW(1:999)/((Sheet2!$B$1:$B$999=A2)*(Sheet2!$C$1:$C$999=B1)), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
For version of Excel prior to 2010 use this standard formula in Sheet1!C1:
=IFERROR(INDEX(Sheet2!$A$1:$A$999, SMALL(INDEX(ROW($1:$999)+((Sheet2!$B$1:$B$999<>A1)+(Sheet2!$C$1:$C$999<>B1))*1E+99, , ), COUNTIFS(A$1:A1, A1, B$1:B1, B1))), "")
I've handled error with the IFERROR function in that latter formula. Excel 2003 and previous may have to use an IF(ISERROR(..., ...)) combination.

Copy every nth line from one sheet to another

I have an Excel spreadsheet with 1 column, 700 rows. I care about every seventh line. I don't want to have to go in and delete the 6 rows between each row I care about. So my solution was to create another sheet and specify a reference to each cell I want.
=sheet1!a1
=sheet1!a8
=sheet1!a15
But I don't want to type in each of these formulas ... `100 times.I thought if I selected the three and dragged the box around, it would understand what I was trying to do, but no luck.
Any ideas on how to do this elegantly/efficiently?
In A1 of your new sheet, put this:
=OFFSET(Sheet1!$A$1,(ROW()-1)*7,0)
... and copy down. If you start somewhere other than row 1, change ROW() to ROW(A1) or some other cell on row 1, then copy down again.
If you want to copy the nth line but multiple columns, use the formula:
=OFFSET(Sheet1!A$1,(ROW()-1)*7,0)
This can be copied right too.
In my opinion the answers given to this question are too specific. Here's an attempt at a more general answer with two different approaches and a complete example.
The OFFSET approach
OFFSET takes 3 mandatory arguments. The first is a given cell that we want to offset from. The next two are the number of rows and columns we want to offset (downwards and rightwards). OFFNET returns the content of the cell this results in. For instance, OFFSET(A1, 1, 2) returns the contents of cell C2 because A1 is cell (1,1) and if we add (1,2) to that we get (2,3) which corresponds to cell C2.
To get this to return every nth row from another column, we can make use of the ROW function. When this function is given no argument, it returns the row number of the current cell. We can thus combine OFFSET and ROW to make a function that returns every nth cell by adding a multiplier to the value returned by ROW. For instance OFFSET(A$1,ROW()*3,0). Note the use of $1 in the target cell. If this is not used, the offsetting will offset from different cells, thus in effect adding 1 to the multiplier.
The ADDRESS + INDIRECT approach
ADDRESS takes two integer inputs and returns the address/name of the cell as a string. For instance, ADDRESS(1,1) return "$A$1". INDIRECT takes the address of a cell and returns the contents. For instance, INDIRECT("A1") returns the contents of cell A1 (it also accepts input with $'s in it). If we use ROW inside ADDRESS with a multiplier, we can get the address of every nth cell. For instance, ADDRESS(ROW(), 1) in row 1 will return "$A$1", in row 2 will return "$A$2" and so on. So, if we put this inside INDIRECT, we can get the content of every nth cells. For instance, INDIRECT(ADDRESS(1*ROW()*3,1)) returns the contents of every 3rd cell in the first column when dragged downwards.
Example
Consider the following screenshot of a spreadsheet. The headers (first row) contains the call used in the rows below.
Column A contains our example data. In this case, it's just the positive integers (the counting continues outside the shown area). These are the values that we want to get every 3rd of, that is, we want to get 1, 4, 7, 10, and so on.
Column B contains an incorrect attempt at using the OFFSET approach but where we forgot to use $. As can be seen, while we multiply by 3, we actually get every 4th row.
Column C contains an incorrect attempt at using the OFFSET approach where we remembered to use $, but forgot to subtract. So while we do get every 3rd value, we skipped some values (1 and 4).
Column D contains a correct function using the OFFSET approach.
Column E contains an incorrect attempt at using the ADDRESS + INDRECT approach, but where we forgot to subtract. Thus we skipped some rows initially. The same problem as with column C.
Column F contains a correct function using the ADDRESS + INDRECT approach.
If I were confronted with extracting every 7th row I would “insert” a column before Column “A” . I would then (assuming that there is a header row in row 1) type in the numbers 1,2,3,4,5,6,7 in rows 2,3,4,5,6,7,8, I would highlight the 1,2,3,4,5,6,7 and paste that block to the end of the sheet (700 rows worth). The result will be 1,23,4,5,6,7,1,2,3,4,5,6,7,1,2,3,4,5,6,7……. Now do a data sort ascending on column “A”. After the sort all of the 1’s will be the first in the series, all of the 7’s will be the seventh item.
insert a new column and put a series in 1,2,3,4, etc. Then create another new column and use the command =if(int(a1/7)=(a1/7),1,0) you should get a 1 in every 7th row, filter the column on the 1
Highlight the 7th line. Paintbrush the format for the first 7 lines a few times. Then do a bigger chunk of paintbrush copying the format until you are done. Every 7th line should be highlighted. Filter by color and then copy and paste (paste the values) from the highlighted cells into a new sheet.
Create a macro and use the following code to grab the data and put it in a new sheet (Sheet2):
Dim strValue As String
Dim strCellNum As String
Dim x As String
x = 1
For i = 1 To 700 Step 7
strCellNum = "A" & i
strValue = Worksheets("Sheet1").Range(strCellNum).Value
Debug.Print strValue
Worksheets("Sheet2").Range("A" & x).Value = strValue
x = x + 1
Next
Let me know if this helps!
JFV
If your original data is in column form with multiple columns and the first entry of your original data in C42, and you want your new (down-sampled) data to be in column form as well, but only every seventh row, then you will also need to subtract out the row number of the first entry, like so:
=OFFSET(C$42,(ROW(C42)-ROW(C$42))*7,0)
Add new column and fill it with ascending numbers. Then filter by ([column] mod 7 = 0) or something like that (don't have Excel in front of me to actually try this);
If you can't filter by formula, add one more column and use the formula =MOD([column; 7]) in it then filter zeros and you'll get all seventh rows.

Resources