This article describes an extremely basic Excel® function (well, two functions actually) and is more a test of my new WordPress installation than anything else
It describes how you can use the INDEX() and MATCH() functions to look up data in a matrix.
Background to VLOOKUP()
Many users are familar with the VLOOKUP() (vertical lookup) function that simply looks up a value in the leading column of a table and returns the value in another specified column of the same table. The required parameters are:
VLOOKUP(Lookup_value,Table_array,Col_index_num,Range_lookup) where Range_lookup is optional.
For example:
With the data in the table below…
| A | B | |
| 1 | Fruit | Colour |
| 2 | Apple | Red |
| 3 | Banana | Yellow |
| 4 | Orange | Orange (what else!) |
…the formula
=VLOOKUP(“Banana”,$A$2:$B$4,2)
Result: Yellow
will search for “Banana” (1st parameter) in the leftmost column of the table ($A$2:$B$4) (2nd parameter) and return the value that is in the 2nd (3rd-parameter) column.
It should be noted that the 1st parameter (the value of which, here, is “Banana“) can also be a cell reference (e.g. $D$1) rather than statically entered into the result cell formula.
Problems with VLOOKUP()
I’ve never like this function for several reasons:
- Any changes to the structure of the table (such as the insertion of a new column) may result in the incorrect field value for that row entry being returned.
- You need to determine what column number the information you want return resides in. (This is obviously fine for small tables, but you shouldn’t have to waste time determining this in the first place!)
- The table needs to be (ascendingly?) sorted by the first column to work correctly.
- It takes longer than it ought to replicate the query to return the value for a different column.
So what are our alternatives? I prefer to use the INDEX() and MATCH() functions. For my mind this approach is not only more flexible, but it’s also more intuitive.
The premise is much the same, however, instead of matching only the leftmost column, you can also match a row and column to determine the coordinates of the value you want returned. It’s effectively a combination of the VLOOKUP() (vertical lookup) and HLOOKUP()* (horizontal lookup) functions.
* HLOOKUP() simply matches a value to the first row (cf. column) of the table, returning the value in a corresponding column (cf. row)
Using INDEX() and MATCH()
I’ll describe the INDEX() and MATCH() functions separately. There are two permutations of the INDEX() function: array and reference. For the purposes of this post, I’ll use array. The INDEX() function is described as:
=INDEX(array,row_num,column_num)
For example:
Using the same data from the previous example, we designate the array parameter as the table that contains the data we wish to return.
| A | B | |
| 1 | Fruit | Colour |
| 2 | Apple | Red |
| 3 | Banana | Yellow |
| 4 | Orange | Orange (what else!) |
To retrieve the same result from the first example, we can use the formula:
=INDEX($A$2:$B$4,2,2)
Result: Yellow
This returns the value from the array ($A$2:$B$4 – 1st parameter) that is in the 2nd row (2nd parameter) and the 2nd column (3rd parameter). Using the function in this way INDEX() is certainly no better than using VLOOKUP() (in fact, it’s worse, because there is no dynamic functionality – that is, there is no “searching” involved.)
So, how do we dynamically determine the row and column numbers based on certain criteria? We can use the MATCH() function, which can be described as:
=MATCH(Lookup_value,Lookup_array,Match_type)
To determine the row we are interested in (here, row 2 – the “Banana” row) we can use the formula:
=MATCH(“Banana“,$A$2:$A$4,0)
This searches the data array ($A$2:$A$4 – the 2nd parameter) for the lookup value (“Banana” – the 1st parameter) and ensures that it matches exactly (Match_type – the 3rd parameter – equals 0; returns #N/A if there is no match.)
Result: 2
Similarly, we use this function to determine our required column number (here, column 2 – the “Colour” column) we can use:
=MATCH(“Colour“,$A$1:$B$1,0)
This searches the data array ($A$1:$B$1 – the 2nd parameter) for the lookup value (“Colour” – the 1st parameter) and ensures that it matches exactly (Match_type – the 3rd parameter – equals 0; returns #N/A if there is no match.)
Result: 2
It should be easy to recognise from this point that for a much larger table, this takes a lot of the guess work out of determining the appropriate column number.
=INDEX($A$2:$B$4,MATCH(“Banana”,$A$2:$A$4,0),MATCH(“Colour”,$A$1:$B$1,0))
Result: Yellow
Accomodating changes to the table structure
As mentioned, one of the advantages of using the INDEX() and MATCH() functions is its ability to adapt when changes are made to the table structure.
| A | B | C | D | |
| 1 | Fruit | Price | Colour | Qty |
| 2 | Apple | $1.50 | Red | 2 |
| 3 | Banana | $2.50 | Yellow | 7 |
| 4 | Orange | $0.80 | Orange (what else!) | 8 |
=INDEX($A$2:$D$4,MATCH(“Banana”,$A$2:$A$4,0),MATCH(“Colour”,$A$1:$D$1,0)) will still return “Yellow” (once columns C and D are accounted for) as the 3rd parameter of the INDEX() function is now 3, while…
=VLOOKUP(“Banana”,$A$2:$D$4,2) will now return $2.50 as this is the value in the 2nd column of the “Banana” row, that is, it hasn’t adapted to the change in table structure.
Using named ranges
I love named ranges (as much as one can love an Excel® function) and using them can simplify even the most complicated formula. I will describe named ranges in more detail in another article, but for the sake of this piece, simply put, named ranges are names that refer to a cell or cell range. Using the above example, you could define or “name” the $A$2:$D$4 cell range as “Data“, $A$1:$D$1 as “Fields“, $A$2:$A$4 as “Fruits“, $B$2:$B$4 as “Prices” and so on. You can name ranges by selecting Insert -> Name -> Define from the Excel® file menu. Once this has been done, your formula simplifies to:
=INDEX(Data,MATCH(“Banana”,Fruits,0),MATCH(“Colour”,Fields,0))
Result: Yellow
An additional example – the best use of INDEX() and MATCH()
This combination of functions is probably best utilised when using 2-dimensional matrices that have column and row headings.
For example:
| A | B | C | D | |
| 1 | Origin/Destination | Sydney | Melbourne | Brisbane |
| 2 | Sydney | 0 | 885 | 926 |
| 3 | Melbourne | 885 | 0 | 1697 |
| 4 | Brisbane | 926 | 1697 | 0 |
With the appropriate named ranges, your formula to determine the distance between two given points could be:
=INDEX(Distances,MATCH(“Brisbane”,Origins,0),MATCH(“Sydney”,Destinations,0))
Results: 926
Other points
- As mentioned with the VLOOKUP() example, “Banana” and “Colour” could both be cell references (you could even use a drop-down menu!)
- You could use VLOOKUP() and MATCH() (e.g. VLOOKUP(“Banana”,$A$2:$B$4,MATCH(“Colour”,$A$1:$B$1,0)) but you are still limited to your “row” search term being in the first row and that the list is sorted by the first row.
- Complications can arise if there are not unique values in a column or row (e.g. “Apples” can be “Red” or “Green“, so could have two entries in the table.) There are ways in which you can handle this (sometimes using SMALL() and BIG() that are beyond the scope of this article.)
Othewise, I’ve found this to be a good alternative to the VLOOKUP() function; one that’s easier to use and more powerful.
There are certainly aspects of the functions that I have omitted. I’d welcome any comments or criticism, so please feel free to add any comments. If you require further clarification on any part of this article, please leave a comment, or you can email me at: ryan@kirgs.com or simply visit my website: http://www.kirgs.com/ and complete the feedback form on the “contact” section.
Ryan Kirgan is a Business Analyst who operates out of Sydney, Australia.

{ 5 } Comments
is it possible for VLOOKUP to have 2 reference(lookup) “B1 and A3” and will look for sheet2 in Columns A and B if it matches the Cells B1 and A3 from sheet1 it will get the value from sheet2 Column C and return to sheet1
SHEET1
1 A B C D E F G H I
2 1 2 3 4 5 6 7 8
3 name1 5
4 name2 6
5 name3 7
6 name4 8
7 name5 9
8 name6 10
9 name7 11
10 name8 12
SHEET2
A B C
1 name1 5
2 name2 6
3 name3 7
4 name4 8
5 name5 9
6 name6 10
7 name7 11
8 name8 12
@Arvin
Hi Arvin,
I’m not too sure what you’re after as the table has become distorted in WordPress, making it difficult to work out what values are in B1 & A3.
Could you email me your spreadsheet to ryan@kirgs.com.
You can certainly use lookup functions across worksheets and you can also match multiple criteria. As with most things, there are many ways to go about doing this, but with a bit more information I can hopefully provide you with a suitable approach – perhaps one that uses INDEX() and MATCH() rather than VLOOKUP()
Ryan
Hi again,
I had a look at the email of your post (that maintained the correct formatting for some reason) and think I have an idea as to what you are after. My interpretation is that you want to match two criteria; the name in the leftmost column of Sheet1 and the number in the top row Sheet1 – if there’s a match in Sheet2, then return the value in the rightmost column of Sheet2.
Lets start with Sheet2 because this is where your raw data is kept. In fact, if it’s ok, I’ll rename the worksheet to Data
Data
At this point, I’d always recommend using named ranges on these columns, but to keep the solution in cell reference terms, we can substitute this in later.
Now, turning our attention to Sheet1 (which I’ll call Output)…
Output
To reiterate, what I think you want to do is populate the coloured cells (containing ???) when there is a match to the column and row. As mentioned, there are more ways to do this than I care to mention, but the first that comes to mind involves using INDEX() and MATCH() (thank goodness, being the title of the blog entry and all
Let’s start by clicking on the first cell we want to calculate on the Output worksheet: B2.
From earlier, INDEX() can be described as:
=INDEX(array,row_num,column_num)
Here, the array we are after is the rightmost column in the Data worksheet (Data!$C$1:$C$8). Being only one column wide, the only column_num we can have is 1. But how do we work out the row_num when there are two criteria? One way to do this is to concatenate the two search terms. You do this by using an ampersand (&). You then concatenate the columns you want to search so you’re comparing apples to apples (so to speak.)
Describing MATCH():
=MATCH(Lookup_value,Lookup_array,Match_type)
So our Lookup_value for this first cell is $A2&B$1. We use the dollar ($) symbol in front of the A in $A1 to confine the search queries to the first column (i.e. the ones with name1…name8 in them). Similarly, we use the dollar ($) symbol in from of the 1 in B$1 to confine the searches to the first row. That way, when we copy the formula to the other cells, we’re always matching the leftmost/top column that corresponds the cell we’re in.
As mentioned, our Lookup_array is also a concatenation, however this time it is Data!$B$1:$B$8&Data!$A$1:$A$8. We have dollar ($) symbols in front of of all row and column references here because the raw data doesn’t move (i.e. its position is not relative the cells).
This results in:
=MATCH(Output!$A2&Output!B$1,Data!$B$1:$B$8&Data!$A$1:$A$8,0)
So…putting it altogether we have:
=INDEX(Data!$C$1:$C$8,MATCH(Output!$A2&Output!B$1,Data!$B$1:$B$8&Data!$A$1:$A$8,0),1)
but pressing return results in #VALUE. This is because concatenating strings in a function such as this returns an array. To formulate cells like this instead of press Enter after entering the formula, you need to press Shift and Enter at the same time. This will put curly brackets ({ and }) around the formula. In doing so, for this example, you should now see the number 5 in B2 which corresponds to the two criteria in the raw data.
You only need to do this once, as we’re going to now place the cursor on the bottom right-hand corner of B2 until the cross appears and will drag the formula to the other cells in the table. You can’t copy and paste the formula to more than one cell as Excel will complain that you “cannot change part of an array.”
The only problem now is that there are #N/As where there isn’t a corresponding value in the raw data
What’s a quick way to get rid of this. What I do is use a simple if statement to return nothing if the result is an #N/A. What I do in this instance is use a combination of the IF() and ISNA() functions.
To describe this in broad terms:
=IF(ISNA(cell value),nothing,something)
i.e. if the cell value is #N/A then return nothing; otherwise, return something. In this case, it’s the MATCH() function that is returning the #N/A, so we only need to use that as the in the above.
Our formula for B2 now becomes:
={IF(ISNA(MATCH(Output!$A2&Output!B$1,Data!$B$1:$B$8&Data!$A$1:$A$8,0)),””,INDEX(Data!$C$1:$C$8,MATCH(Output!$A2&Output!B$1,Data!$B$1:$B$8&Data!$A$1:$A$8,0),1))}
(without the curly brackets – these are put in the cells formula after pressing Shift + Enter.
As you can see, this formula is ridiculously long. Named ranges will improve this. For instance defining:
dataID => Data!$A$1:$A$8
dataName => Data!$B$1:$B$8
dataResult => Data!$C$1:$C$8
reduces the formula to:
={IF(ISNA(MATCH($A2&B$1,dataName&dataID,0)),””,INDEX(dataResult,MATCH($A2&B$1,dataName&dataID,0),1))}
Output
Hopefully this is what you were after
You can download the file from here: Multiple Criteria INDEX MATCH demo for Alvin.xls (22k)
I thought about this a bit more…
If you don’t want to use INDEX() and MATCH() you might like to try:
=SUMPRODUCT(($A2=dataName)*(B$1=dataID)*(dataResult)) in B2. It’s not an array formula (so no Ctrl + Shift + Enter) and it’s a lot more intuitive.
Where there’s no match, you’ll see a 0. You can hide these in a number of ways:
1. =IF(SUMPRODUCT(($A2=dataName)*(B$1=dataID)*(dataResult))=0,”",SUMPRODUCT(($A2=dataName)*(B$1=dataID)*(dataResult)))
2. Select the cells, right-click and select “Format Cells”. From the “Custom” menu, append two semi-colons to the format. e.g. “General” becomes “General;;”
Plus others.
Post a Comment