How to encapsulate INDIRECT into INDEX using R/C notation in Excel? - excel

I created a range using INDIREKT, I added COL() to see how big this range is:
=COL(INDIRECT("R1C1:R1C5"; 0))
As you can see, I'm using the R/C notation for row/colum adressing. The result is simply all numbers from 1 to 5 in the first row:
Now I'm just using the numbers to address letters from a string, like this:
="_" & MID("HELLO"; COL(INDIRECT("Z1S1:Z1S5"; 0)); 1)
This works as expected and returns:
Now there's a random cell somewhere on the sheet, I named this cell "_H". The cell just contains the letter H:
I did this for E, L and O, too.
Now I add a third row containing this.
=INDEX(INDIRECT(A2);1;1)
Pulling this to the width of 5 columns the result is as expected:
And here comes my problem: How to use the R/C notation? This comes into my mind:
=INDIRECT("Z2S1"; 0)
This returns the correct value of row 2, column 1 aka A2. Which is _H. Now I put this into the INDEX formula, expecting that Excel takes the _H, use this as the address for INDEX and returns the value from 1;1 of this "name range":
=INDEX(INDIRECT("R2C1";0);1;1)
But the result is simply:
When I remove the quotes, Excel is complaining, so this is not working:
=INDEX(INDIRECT(R2C1;0);1;1)
(Apparently, because the Excel setting says I prefer A1-notation).
But I wonder why it's not working, when I tell excel explicitly to use the R/C notation?
Well, it seems like Excel just takes the range and the value from R1C1 in this range - which is _R. So I was trying around to make this column-argument "dynamic". I know that this returns the column index for the whole range.
=COL(INDIRECT("R1C1:R1C5";0))
This returns 1, 2, 3, 4 and 5 for the particular columns.
So why not putting it into the formula above:
=INDEX(INDIRECT("Z2S" & COL(INDIRECT("R1C1:R1C5";0));0);1;COL(INDIRECT("R1C1:R1C5";0)))
This returns #VALUE as an error.
How to indirectly address a cell or even a range to get a value from a particular coordinate (using INDEX)? I specifically need the R/C notation because I need to address ranges numerically (for example column 1 instead of column A and so on).

You can condense your solution - no `INDEX(X;1;1) needed:
=LET(word,"HELLO",
singleCharacters,"_" & MID(word,SEQUENCE(1,LEN(word)),1),
MAP(singleCharacters,LAMBDA(a,INDIRECT(a))))
Using LET makes it a bit more readable.

Ok, it's easier than I thought, Excel has this wonderful MAP formula:
=MAP(A2:E2; LAMBDA(a; INDEX(INDIRECT(a); 1; 1)))
Now every particular column points to the reference/range name and INDEX can use this, to get the value from R1/C1 of the particular named range.
This can even be more improved into a one-liner:
=MAP(SEQUENCE(1;LEN("HELLO")); LAMBDA(i; INDEX(INDIRECT("_" & MID("HELLO"; i; 1));1;1)))
I can put this everywhere I want, I just need to define the named ranges.
Appreciation to #Ike who lead into the right direction.

Related

In excel, can you create a named range from multiple values (linestring) within a single cell?

I was wondering if I can make a named range from a linestring in a single cell, like "1,2,3,6,7" or "1-3, 6-7", instead of having to type each value in its own cell.
In column C of sheet A, I want to sum the values of column B if the values of column A exists in my named range "B_range", otherwise it will be 0. I use the formula:
=if(count.if(B_range,A2)>0,sumproduct(sum.if(A:A,B_range;B:B)),0)
"B_range" consists of C2:E2 in Sheet B, but if possible, I would like to define "B_range" from the textstring values in B2 of sheet B.
This could be quite a tricky problem. A line like '2,3,4' not so much, but '1-3, 5,7` is allready much more problematic, let alone a combination of the two.
It is allready made easier if you'd have access to LET() and microsoft 365's dynamic arrays:
Formula in C2:
=LET(A,TRANSPOSE(MID(FILTERXML("<t><s>'"&SUBSTITUTE(E1,",","</s><s>'")&"</s></t>","//s"),2,LEN(E1))),B,--LEFT(A,FIND("-",A&"-")-1),C,IFERROR(--MID(A,FIND("-",A)+1,99),--A),D,MMULT((A2:A6>=B)*(A2:A6<=C),SEQUENCE(COUNTA(A),,,0)),IF(D,SUM(B2:B6*D),0))
Variables explained:
A - TRANSPOSE(MID(FILTERXML("<t><s>'"&SUBSTITUTE(E1,",","</s><s>'")&"</s></t>","//s"),2,LEN(E1))) will break up your initial string in an horizontal array. In our case {2,3,4,6-8}.
B - --LEFT(A,FIND("-",A&"-")-1) will retrieve the number on the left of the hyphen. Note that we concatenate variable 'A' with an hyphen for this purpose. The result: {2,3,4,6}.
C - IFERROR(--MID(A,FIND("-",A)+1,99),--A) will retrieve the number right of the hyphen. When no hyphen, the same as variable 'A' is returned: {2,3,4,8}.
D - MMULT((A2:A6>=B)*(A2:A6<=C),SEQUENCE(COUNTA(A),,,0)) will calculate if any of your 'Nr.'s are to be found inbetween the previous two variables 'B' and 'C'. An vertical array is returned: {0;1;1;1;0}.
IF(D,SUM(B2:B6*D),0) - Our final calculation is a simple IF() statement which will use D and spill the results down under 'Sum'.
I can get into much more detail, but the above should give you an idea of what happened here.
For those who find it interesting how to 'split' a string into an array, please follow this link.

How to compare one cell with a range and if TRUE - copycontent from the right cell?

I need to compare two columns I and L and copy matched result from M column. It is a list of 1000+ product codes (I,L) and EAN codes (M). So if cell I1 is found in range of L1:L1000 (lets say it found in L3 cell), then formula should copy the M3 cell.
Tried VLOOKUP and MATCH and some IF, but cannot figure it out how to make it work as it returns blank or REF! or N/A or errors-out completely. I'm desperate and don't know what i'm doing wrong...
=VLOOKUP(I1:I1164,L1:L1164,13,FALSE)
and with
=IF(ISNUMBER(SEARCH(I1,L1:L1000),M1," "")
Result should be in N column.
When using VLOOKUP, you need the lookup range to include both the range of values you're looking for (which MUST to be the first column) and the return values (whose column you specify as relative to the range. So in your case, you'll be looking up in L1:M1164 and using column 2 as return results (since column M is the second of L1:M1164).
Also, the value you're looking for will probably be just an item, relative to the current line. I'd thus try it that way (in N1):
=VLOOKUP(I1;$L$1:$M$1164;2;FALSE)
Wrapping it up in an IFERROR as suggested in SJR's answer might be a good idea too.
Try this
=iferror(index(m1:m1000,match(i1,l1:l1000,0)),"")
The match bit returns 3, the index bit then looks for the 3rd value in column M; the Iferror returns an empty string in the event of an error (i1 is not found).

Three Dimensional Lookup Using INDEX/MATCH

This was taken and improved slightly from Question that has since been deleted
For those who can see deleted posts, it was taken from here: https://stackoverflow.com/questions/39793322/three-dimensional-lookup-no-concatenate-or-named-ranges-excel
I'm trying to do a three dimensional lookup without named ranges or concatenates. Simplified, my data is on the form:
Column1 Column2 Column3
Scott
P 1 2 3
M 4 5 6
N 7 8 9
George
P 10 11 12
M 13 14 15
N 16 17 18
I now want to search for a specific Name and then for a specific letter within that names table, I then want to match this row number with a specific column.
I tried a simple INDEX/MATCH:
=INDEX(A:D,MATCH("M",A:A,0),MATCH("Column1",1:1,0))
And that works for the fist name but not any others as it finds the first instance of M.
How do I modify it to look for a different name?
I have answered below, but want to see if someone has a better solution.
I used an IF() statement array formula to find what the P row number was after the George row... I also needed to use the MIN() function to get the first P row number after the name.
Beyond that, it's a simple INDEX() function.... that racked my brain for over an hour :).
=INDEX($A$1:$D$9,MIN(IF((ROW(A1:A9)>MATCH($F$4,A1:A9,0))*(A1:A9=$F$5),ROW(A1:A9),"")),MATCH($F$6,$A$1:$D$1,0))
Don't Forget!
Use Ctrl+Shift+Enter when finishing the formula, so it gets evaluated as an array formula.
You can use two other INDEX/MATCH's inside the first MATCH to set the lookup range. Then you simply need to add the MATCH() to find the absolute position of the name.
=INDEX(A:D,MATCH($H$4,INDEX(A:A,MATCH($H$3,A:A,0)):INDEX(A:A,MATCH($H$3,A:A,0)+4),0)+MATCH($H$3,A:A,0)-1,MATCH($H$5,$1:$1,0))
This one works better and does not have a size constraint:
=INDEX(A:D,MATCH(F4,INDEX(A:A,MATCH(F3,A:A,0)):A1040000,0)+MATCH(F3,A:A,0)-1,MATCH(F5,A1:D1,0))
You can do this just by adding the results of two matches together. One match for the names plus one match for the letter equals the total row.
=INDEX(A:D,MATCH(G5,A3:A5,0)+MATCH(G3,A:A,0),MATCH(G4,1:1,0))
In other words: Index(All of the Data, Match(Name, In name column, exact) + Match(Letter, In letter column, exact), Match(Column name, in Column row, exact)
Screen capture of working sheet
My answer attempts the general case with only one caveat:
That a letter is single character text, and a name is more than 1 character. Otherwise i feel there is no difference logically between letters and names, and it is then impossible to really do...
RE-EDIT for better function construction:
{=INDEX($A$1:$D$17, MATCH($H$3,$A1:$A17, 0)+MATCH($H$4, INDEX($A1:$A17, MATCH($H$3,$A1:$A17, 0)):INDEX($A:$A, SMALL(IFERROR(MATCH($H$3,$A1:$A17, 0)+POWER(SQRT(IF(LEN($A$1:$A$17)>1, ROW($A$1:$A$17), 0)-MATCH($H$3,$A$1:$A$17, 0)), 2)-1, ROWS($A$1:$A$17)), 2)), 0)-1, MATCH($H$5, $A$1:$D$1, 0))}
This uses an array formula along column A, and checks if the length is > 1 and throws the row nums into an array, with letters given a 0.
Then match row of unique name(e.g. George) is subtracted from each.
We then use a min(of all other name rows, with the last data row as the final default - SMALL function with 2 parameter) to find the next name row(or last data row if there is no following name).
Rest is standard index/match etc.
It will correctly return #N/A if there is no such letter under the chosen name...
My dataset is A1:A17, and the formula could use A:A instead each time, but the array calc inside the IF needs the A1:A17 for speed.
EDIT for better function construction:
If we wanted to avoid editing the formula when the data length changes, then we could let full column references of A:A go through the entire construction(and lose speed/efficiency) with the last data row in colA calculated via ROWS(A:A):
Re-edit:
{=INDEX($A:$D, MATCH($H$3,$A:$A, 0)+MATCH($H$4, INDEX($A:$A, MATCH($H$3,$A:$A, 0)):INDEX($A:$A, SMALL(IFERROR(MATCH($H$3,$A:$A, 0)+POWER(SQRT(IF(LEN($A:$A)>1, ROW($A:$A), 0)-MATCH($H$3,$A:$A, 0)), 2)-1, ROWS($A:$A)), 2)), 0)-1, MATCH($H$5,1:1, 0))}
It really depends on the setup...
Edit again for version which takes blanks as separators for names
If you want to use blanks as the separator for names, where no blanks are in the data results, but blanks appear in columns B to D where there is a name, then a tiny change in the above formulae will result in this:
=INDEX($A$1:$D$17, MATCH($H$3,$A$1:$A$17, 0)+MATCH($H$4, INDEX($A:$A, MATCH($H$3,$A:$A, 0)):INDEX($A:$A, SMALL(IFERROR(MATCH($H$3,$A:$A, 0)+POWER(SQRT(IF($B$1:$B$17="", ROW($A$1:$A$17), 0)-MATCH($H$3,$A$1:$A$17, 0)), 2)-1, ROWS($A$1:$A$17)), 2)), 0)-1, MATCH($H$5, $A$1:$D$1, 0))
This means that the names and letters do not have to be any specified length, but just one proviso is that blanks appear in the row with the name.
A small amendment to the condition to find the end range to search for the letter by replacing this: SQRT(IF(LEN($A$1:$A$17)>1, with this:
SQRT(IF($B$1:$B$17="",
I would use the area (4th parameter) of Index(). Below is a screenshot of test data. This example assumes the same columns and keys are sorted and consistent.
This works by using (Range1,Range2) as the first parameter of index. For the 4th parameter of index, use N for which area in the () you want Index to return.
I think this may be slightly tidier, and a little easier to modify maybe.
=INDEX(OFFSET(INDIRECT("A"&MATCH($H$3,$A:$A,0),TRUE),0,0,4,4),MATCH($H$4,$A:$A,0),MATCH(H5,$1:$1,0))
Using offset to create the range first, we're able to use the name from H3 to set that up, and then beyond that we are just indexing within that new range.
Now this is still dependendent on staying in Column A for the names.
Assuming the format of the data is always Name then P, M and N this formula does the work:
=INDEX($A:$D,
MATCH($H$3,$A:$A,0)
+LOOKUP($H$4,{"P",1;"M",2;"N",3}),
MATCH($H$5,$1:$1,0))
This solution works on almost all conditions. One restriction I found is when one of the subjects (Names) does no have data for any of the details (letters), but as of now the same occurs with all the other answers.
The formula assumes the data is located at B6:F30 (in order to ensure it can be applied regardless of the source range location).
The formula uses the Index\Match functions:
First, a MATCH to retrieve the position of the Name:
MATCH($H8,$B$6:$B$30,0)
With that info it uses INDEX to build a range that is used to obtain the position of the Detail (letter) using a second MATCH Function:
+ MATCH($I8,INDEX($B$6:$B$30, 1 + MATCH($H8,$B$6:$B$30,0))
:INDEX($B$6:$B$30,ROWS($B$6:$B$30)),0),
Adding the results of the first and second MATCH functions obtains the position of the Name`Detail` combination and uses it in an Index to the entire data. The position of the Data Column required is obtained with a Match:
INDEX($B$6:$F$30, 1st.MATCH + 2nd.MATCH,
MATCH(J$6,$B$6:$F$6,0))
With the results located at G6:L30 enter this formula in J8 then copy to J8:L30:
= INDEX( $B$6:$F$30,
MATCH( $H8, $B$6:$B$30, 0)
+MATCH( $I8, INDEX( $B$6:$B$30 , 1 + MATCH( $H8, $B$6:$B$30 ,0))
: INDEX( $B$6:$B$30, ROWS($B$6:$B$30) ),0),
MATCH( J$6, $B$6:$F$6, 0)),"")
This solution works in all conditions discussed so far (let me know of any condition that it does not work and I’ll try to cover it).
I’m posting this as a separated answer as the formulas applied in prior answer rightly apply to the conditions stated in them, as such they will be useful to users with those specific scenarios, so they don’t need to apply these long formulas.
This formula assumes the data is located at B6:E30 (in order to ensure it can be applied regardless of the source range location).
This formula uses the Index\Match functions and it’s a Formula Array.
FormulaArrays are entered pressing [Ctrl] + [Shift] + [Enter] simultaneously, you shall see { and } around the formula if entered correctly
Syntax:
=IFERROR(INDEX(DataRng,
MATCH(Value1,NamesRng,0)
+IFERROR(MATCH(Value2,INDEX(NamesRng,
1+MATCH(Value1,NamesRng,0))
:INDEX(NamesRng, IFERROR(MATCH(Value1,NamesRng,0)
+MATCH("#",IF((INDEX(Col1Rng,1+MATCH(Value1,NamesRng,0))
:INDEX(Col1Rng,ROWS(NamesRng)))="","#","!"),0),
ROWS(NamesRng))),0),NA()),MATCH(ValCol,DataHdr,0)),"")
Arguments:
Assuming the data is located at B6:E30.
Value1= Name to be found in Data, i.e. George, Scott, etc.
Value2= Detail to be found in Data, i.e. Detail1, Detalle2, etc.
ValCol = Column to be found in Data i.e. Column1, Column2, etc.
DataRng= $B$6:$E$30
DataHdr= $B$6:$E$6
NamesRng= $B$6:$B$30
Col1Rng= $C$6:$C$30
1st MATCH: Retrieves the position of the Name:
MATCH(Value1,NamesRng,0)
2nd MATCH: Retrieves the end position of the Name’s corresponding Details, which is determined by a blank value in column C or the end of the data range:
MATCH("#",IF((INDEX(Col1Rng, 1 + 1stMATCH)
:INDEX(Col1Rng,ROWS(NamesRng)))="","#","!"),0),
Builds a Range (vRange): With the Names's Details using the 1st and 2nd match functions. If 2nd Match returns an error then it uses the last row of the Data range:
INDEX(NamesRng, 1 + 1stMATCH )
:INDEX(NamesRng, IFERROR( 1stMATCH + 2ndMATCH, ROWS(NamesRng)))
3rd MATCH: Retrieves the position of the Detail within the vRange. It returns #NA if the combination is not present.
IFERROR(MATCH(Value2, vRange,0), NA())
Adding the results of the 1st and 3rd match functions obtains the Row index of the Name`Detailcombination or#NAif no found.
The Column index is obtained with a Match from the Header of the Data.
It then applying the INDEX function to the Data Range returns the value of theName\Detail\Columncombination.
If theName\Detail` combination is not found it returns blank.
=IFERROR( INDEX( DataRng, 1stMATCH + 3rdMATCH, MATCH(Column,DataHdr,0)),"")
With the results located at H6:L37 enter this Formula Array in J8 then copy to K8:L37 and to J9:L37:
=IFERROR( INDEX($B$6:$E$30,
MATCH($H8,$B$6:$B$30,0)
+IFERROR( MATCH($I8, INDEX($B$6:$B$30,
1+MATCH($H8,$B$6:$B$30,0))
:INDEX($B$6:$B$30, IFERROR(MATCH($H8,$B$6:$B$30,0)
+MATCH("#", IF((INDEX($C$6:$C$30,1+MATCH($H8,$B$6:$B$30,0))
:INDEX($C$6:$C$30,ROWS($B$6:$B$30)))="","#","!"),0),
ROWS($B$6:$B$30))),0),NA()),
MATCH(J$6,$B$6:$E$6,0)), "")
Wow... So many solutions already.
I think a simpler solution could be using offset to get a more generic answer.
=INDEX($A$1:$D$9, MATCH($G$3,OFFSET($A$1,MATCH($G$2,$A$1:$A$9,0),0,3,1),0)+MATCH($G$2,$A$1:$A$9,0), MATCH($G$4,$B$1:$D$1,0)+1)
The only variable to look for is 3 which is the number of M/N/P options present because that will affect the number of rows. Otherwise, the solution works fine in all possible scenarios and different orders.
When I have more than two inpunts for a data search I prefer to have the data organized as shown in the figure, so that I can use a pivot table and get it to organize the data in rows and columns as I like.
Then I use GETPIVOTDATA to search for a value.
Cell G9 contains this formula:
=GETPIVOTDATA("Value";$F$3;"Name";G15;"Letter";G16;"Column";G17)

Looking up a value in a specified column

Something I've wanted to do quite a bit lately, and can't work out how to do, is MATCH in a column I pass as an argument. Essentially, I have a two dimensional array, and I want to be able to find the first occurrence of a given value in the nth column, for any given value of n, and return the row number it occurs at. Alternatively (and more-or-less equivalently), I want to be able to search in the column with a given column header. Is there any way to do this?
Effectively, I want to simulate the non-existent function =MATCH(lookup_value,lookup_array,lookup_column,[match_type])
I've kludged together a horrible bodge job using INDIRECT, which works, but offends me horribly.
=MATCH(lookup_value,INDIRECT("R"&<top of array>&"C"&<left of array>+<column reference>&":R"&<bottom of array>&"C"&<left of array>+<column reference>,FALSE),FALSE)
This formula should work for you and will avoid INDIRECT. Anytime you can avoid using Indirect, I recommend doing so.
=MATCH(lookup_value,INDEX(lookup_array,0,MATCH(lookup_header,array_headers,0)),0)
If you aren't looking up the column by column header and just have the column number, then it becomes easier:
=MATCH(lookup_value,INDEX(lookup_array,0,column_number),0)
You could do something like this:
Set findCell = ActiveSheet.Range("A:Z").Find(What:="term_to_search")
Will select a header based on your search term.
Set range = ActiveSheet.Range(findCell, findCell.Offset(DEF_MAX_ROWS, 0))
Set up a range which will search from that header down a whole column.
For column references beyond Z you might switch notation (Excel Options, Formulas, Working with formulas and check R1C1 reference style) and, assuming the value to be looked up is in 'A1' (R1C1) with the column number in 'A2' (R2C1) apply:
=MATCH(R1C1,INDIRECT("C"&R2C1,0),0)
to save some complexity in converting a string of two or three characters into the relevant column number.
Say we have a two dimensional array: B3:E17 and we wish to locate Happiness in the third column of that array.In G1 enter:
B3:E17
In G2 enter:
3
In G3 enter:
=ADDRESS(ROW(INDIRECT(G1)),COLUMN(INDIRECT(G1))+$G$2-1) & ":" & ADDRESS(ROW(INDIRECT(G1))+ROWS(INDIRECT(G1))-1,COLUMN(INDIRECT(G1))+$G$2-1)
This will display the address of that third column. Then in G4 enter:
=MATCH("Happiness",INDIRECT(G3),0)
For example:
You can specify a range in a formula using the INDIRECT function. So, for example, if you put the letter designation for the column you want to search in cell A75, you could use:
=MATCH("Value_To_Match", INDIRECT(A75 & ":" & A75), 0)
So, if the value in A75 is G, the string built up in the INDIRECT call is G:G, and the MATCH will look through column G for "Value_To_Match" and return the row number in which it's found.
Using this idea, you can put a formula into A75 that generates the column designation for the column you want to search. For example, if your column headers are all in row 1, and the header you want to search for is in A74, you can do:
=CHAR(MATCH(A74, 1:1, 0) + 64)
using the CHAR function to convert numbers into ASCII characters, so 65 becomes A, 66 becomes B, etc. Note that this will only work if you don't have columns past Z. You'd need a more fussy formula to do the right thing with AA, etc.
You can overcome the annoyances of dealing with column letters by using R1C1 notation instead, which you can activate by adding a second parameter of FALSE to the INDIRECT expression. Now, instead of specifying your column by a letter, you'll specify it using a number. This simplifies the column-finder in A75:
=MATCH(A74, 1:1, 0)
and also the INDIRECT expression in your overall MATCH:
=MATCH("Value_To_Match", INDIRECT("C" & A75, FALSE), 0)

lookup Data in Excel

I have a 2 variable 100x100 data table in excel.
I need to have a function that returns all the possible sets of variables that yield a given target value.
What I am looking at is some kind of a reursive 2 dimensional lookup function. Can someone point me in the right direction?
It can be done without VBA, fairly compactly, like so.
Suppose your 100x100 table is in B2:CW101, and we put a list of numbers 1 to 100 down the left from A2 to A101, and again 1 to 100 across the top from B1 to CW1
Create a column of cells underneath, starting (say) in B104
B104=MAX(($A$2:$A$101*100+$B$1:$CW$1<B103)*($B$2:$CW$101=TargetValue)*($A$2:$A$101*100+$B$1:$CW$1))
This is an "array" formula,so press Ctrl-Shift-Enter instead of Enter, and curly brackets {} should appear around the formula.
Then copy down for as many rows as you might need. You also need to put a large number above your first formula, i.e. in B103, e.g. 999999.
What the formula does is to calculate Rowx100+Column, but only for each successful cell, and the MAX function finds the largest result, excluding all previous results found, i.e. it finds the target results one at a time, starting from bottom right and working up to top left. (With a little effort you could get it to search the other way).
This will give you results like 9922, which is row 99, column 22, and you can easily extract these values from the number.
There is no built-in function that will do what you want, I'm 99% sure of that.
A VBA function that returns an array could be built, along the lines of the quick-and-dirty Sub already shown. Create an Variant to hold the output, perhaps Redimmed to the maximum possible number of results and Redim Preserve-d down to the actual number at the end. Then return that as the result of the function which then needs to be called as an array function (Control-Shift-Enter).
One down-side is that you'd have to ensure that the target range was large enough to hold the entire result: Excel won't do that automatically.
Would the Solver suit?
http://office.microsoft.com/en-us/excel/HA011118641033.aspx
I tried this a lot without using VBA but doesn't seem to be possible without it.
To solve this issue , I needed to loop through the entire array and found closest values. These values were then derefernced using calls and range properties and the output was generated in a range being incremented at each valid match.
The quick and dirty implementation is as under:
Dim arr As Range
Dim tempval As Range
Dim op As Integer
Set arr = Worksheets("sheet1").Range("b2:ao41")
op = 1
Range("B53:D153").ClearContents
For Each tempval In arr
If Round(tempval.Value, 0) = Round(Range("b50").Value, 0) Then
Range("b52").Offset(op, 0).Value = Range("a" & tempval.Row).Value
Range("b52").Offset(op, 1).Value = Cells(tempval.Column, 1).Value
Range("b52").Offset(op, 2).Value = tempval.Value
op = op + 1
End If
Next
Range("b50").Select
I am still looking for an approach without VBA.
I've got a solution that doesn't use VBA, but it's fairly messy. It involves creating a further one-dimensional table in Excel and doing lookups on that. For a 100x100 data table, the new table would need 10,000 rows.
Apologies if this doesn't fit your needs.
A summary is below - let me know if you need more detail. N = the dimension of the data, e.g. 100 in your example.
First, create a new table with five columns and NxN rows. In each case, replace my column names with the appropriate Excel reference
The first column (call it INDEX) simply lists 1, 2... NxN.
The second column (DATAROW) contains a formula to loop through 1, 2... N, 1, 2...N... This can be done using something like =MOD(INDEX-1, N)+1
The third column (DATACOL) contains 1, 1, 1... 2, 2, 2... (N times each).
This can be done with =INT((INDEX-1)/N)+1
The fourth column (VALUE) contains the value from your data table, using something like:
=OFFSET($A$1, DATAROW, DATACOL), assuming your data table starts at $A$1
We have now got a one-dimensional table holding all your data.
The fifth column (LOOKUP) contains the formula:
=MATCH(target, OFFSET(VALUERANGE, [LOOKUP-1], 0),0)+ [LOOKUP-1]
where [LOOKUP-1] refers to the cell immediately above (e.g. in cell F4 this refers to F3). You'll need a 0 above the first cell in the LOOKUP column.
VALUERANGE should be a fixed (named or using $ signs) reference to the entire VALUE column.
The LOOKUP column then holds INDEX numbers which can be used to look up DATAROW and DATACOL to find the position of the match in the data.
This works by searching for matches in VALUERANGE, then searching for matches in an adjusted range starting after the previous match.
It's much easier in a spreadsheet then via the explanation above, but that's the best I can do for the moment...

Resources