Good afternoon,
I am pulling a fuel database from gasbuddy and trying to use the VLOOKUP function to grab address, prices and times last updated. However, all I am getting are #N/A (value not available) results. My code is below:
=VLOOKUP(
N5,
GasPriceSearch.aspx?typ_adv_fuel_limit_36,
COLUMN(B5),
FALSE)
I tried converting this information into a table and the formula works but I run into issues where new fuel prices are reported and it messes up the entire table. I would rather do it from the initial data without a table.
Thank you,
Jesse
There are several ways to achieve this. However, based on your data structure, a regular VLOOKUP won't work because VLOOKUP only searches to the right of the lookup value (i.e., the address) and, for example, the price is to the left of it. Thus, one possibility would be to restructure your data so that you have address, price, update, and so on. This would also circumvent the problem of having the price on a different row than the lookup value.
Another way to work with this data structure is to use the INDEX function:
=INDEX(array, row_num, [column_num])
Your array reflects the range where your data is stored that you want to look up; in your case, considering only price and station A:B. Since you've hidden some columns, it's hard to see what else is in this datasheet. But just adjust it to your needs of the data.
The row number can be hard coded. However, since you want to look up a specific value (i.e., address), you can use the MATCH function:
=MATCH(lookup_value, lookup_array, [match_type])
In this step you want to look up your address from column N in column B, where all stations are listed. You also need to specify the column you want to return. Again, you can either hard code it or use the MATCH function. With the match_type you can specify, for example, that you only want an exact match, i.e., match_type = 0.
To return the value "update" to the left of the address, your formula looks as follows:
=INDEX($A:$B,MATCH(N6,$B:$B,0),1)
To return the address itself (which is pretty much useless, since you already have it in column N), use the following formula with the adjusted column value from 1 to 2:
=INDEX($A:$B,MATCH(N6,$B:$B,0),2)
Lastly, your price information is one row above the address, you need to adjust the number of rows by -1 accordingly. That is, if your address is, for example, 4123 Town [...], you want to return column 1 of row 6 and not row 7:
=INDEX($A:$B,MATCH(N6,$B:$B,0)-1,1)
An alternative strategy would be to use the XLOOKUP function (only available in newer versions of Excel), which allows you to find values to the left of the lookup value. But also with this strategy you would have to deal with the problem of row differences. The OFFSET function could prove useful in this context, but it does not make the approach much easier than the INDEX function.
Related
I am trying to find the closest value in this Poisson Distribution table to help create some variation in my NHL game simulator. Right now I have the minimum value set to =(MAX(H4:R14)/1.25) and the max as MAX(H4:R14). My rand (random) value is set to =RAND()*($V$4-$U$4)+$U$4. My question is, is how do you find the closest value in the table when compared to the random value? Returning the closest match (percentage) is ideal and the table's values will change whenever the teams change. Eventually, I am trying to return the respective column and row values (goals for each team), but this is step 1 and haven't been able to figure it out yet - even with index and match. Feel like it should be fairly straightforward...
You may benefit from SUMPRODUCT and array formula to get closes match and goals values in rows and section. Just as example:
The upper table would be your data. The bottom table is just to check it it works, you can delete. This bottom table is just an absolute value of cell minus your rand. The minimun one is highlighted in green and that's the closest match. Notice how the formulas get the position of that match and the goals values:
Formula to get ROW VALUE:
=SUMPRODUCT(--(ABS(H4:R14-U6)=MIN(ABS(H4:R14-U6)))*G4:G14)
Formula to get COLUMN VALUE:
=SUMPRODUCT(--(ABS(H4:R14-U6)=MIN(ABS(H4:R14-U6)))*H3:R3)
Both of this formulas are array formulas, so to introduce them yo must press CTRL+ENTER+SHIFT or they won't work!
To get the closest match is just INDEX classic formula (we add +1 due to goals indexed as 0,1,2...):
=INDEX(H4:R14,U9+1,V9+1)
See it working!:
I've uploaded the file in case you want to check the formulas:
https://docs.google.com/spreadsheets/d/1wV8bn6B-jZ4jCxAonGdWFMluAEybzwkA/edit?usp=share_link&ouid=114417674018837700466&rtpof=true&sd=true
Please, notice this will work properly as far as there is a single closest match. If by any case two cells are both closest match, formula will return incorrect result.
And remember, as I said before, second table is just to explain the solution, you can delete it and everything will work.
You could create a 2nd table where you calculate the absolute or squared difference between your Poisson table values and the random value.
Then you can simply check for the smallest value in the 2nd table.
In your example, the 2nd table of differences could be created with the formula
=ABS($H$4:$R$14-$U$6)
Let's assume that this 2nd table is just below the 1st table, i.e. in H16:R26
Then the smallest value in this 2nd table is obtained by
=SMALL($H$16:$R$26,1)
from there you can get the row number through
=SUM(($H$16:$R$26=SMALL($H$16:$R$26,1))*($G$4:$G$14))
and the column number through
=SUM(($H$16:$R$26=SMALL($H$16:$R$26,1))*($H$3:$R$3))
Then, to find the closest match in the original table, you can use the INDEX() function and refer to the row and column calculated in the previous step.
You can of course skip all the intermediary steps and write everything into a single formula:
=LET(
table,$H$4:$R$14,
diff,ABS(table-$U$6),
closest,SMALL(diff,1),
closest_row,SUM((diff=closest)*SEQUENCE(ROWS(table))),
closest_col,SUM((diff=closest)*SEQUENCE(1,COLUMNS(table))),
INDEX(table,closest_row,closest_col)
)
Which looks like this:
Note: the last formula uses dynamic arrays and functions only available Excel O365.
I have a sheet with transactions. Each txn has an airport and an amount of fuel pumped. I have a second sheet with a list of locations, each row of which has min and max values for fuel bands (e.g, 1-500, 501-1000, min/max stored in separate columns), and each each of which have a price (for fuel per gallon).
I need to use the values per row in the first spreadsheet to search the second spreadsheet for a match on airport (ICAO code), greater than bottom of band, and less than top of band, and then return the unit price of fuel. The catch is that I can have multiple matches, and I need the smallest/lowest value.
I have some familiarity with Index/Match multi criteria arrays. So, I wrote the following and tried it:
=INDEX(FuelPrices!$D$2:$D$3398,MATCH(1,(FuelPrices!A:A=H2)*(FuelPrices!B:B>=N2)*(FuelPrices!C:C<=N2),0))
Where "Fuel" is my first sheet and "FuelPrices" is the sheet I'm looking up the values in. No matter WHAT I do it throws an #NA error. So, I figured maybe the problem was I was returning an array? I tried this:
=INDEX(FuelPrices!$D$2:$D$3398,SMALL(MATCH(1,(FuelPrices!A:A=H2)*(FuelPrices!B:B>=N2)*(FuelPrices!C:C<=N2),0),1))
Figuring it would give me the smallest value from the returned array. No go. I've tried some other tricks (using another Index function around the match) and nothing seems to work.
Basically I just want to get the function to return the lowest matching value for the provided criteria.
The short answer is that the < and > are the wrong way round. This does give an answer
=INDEX(FuelPrices!$D$2:$D$10,MATCH(1,(FuelPrices!$A$2:$A$10=H2)*(FuelPrices!$B$2:$B$10<=N2)*(FuelPrices!$C$2:$C$10>=N2),0))
if entered as an array formula using CtrlShiftEnter
I have changed all ranges to a small number of rows for testing purposes.
FuelPrices sheet
Fuel sheet
If you do want to find the smallest subject to the same conditions, you don't need index but can use small (or min)
=SMALL(IF((FuelPrices!$A$2:$A$10=H2)*(FuelPrices!$B$2:$B$10<=N2)*(FuelPrices!$C$2:$C$10>=N2),FuelPrices!$D$2:$D$10),1)
Or if you prefer you can use Aggregate (non-array formula)
=AGGREGATE(15,6,FuelPrices!$D$2:$D$10/((FuelPrices!$A$2:$A$10=H2)*(FuelPrices!$B$2:$B$10<=N2)*(FuelPrices!$C$2:$C$10>=N2)),1)
Summary
I need an array formula that takes a row of data of certain length from Sheet1. For that row, in each column that is not blank, I need to grab the Sheet1 header value for that column and display that data in a continuous row on Sheet2 (without any spaces in between the row's cells).
Background
I have a table of data (employees and industry certifications with expiration date being the table's cell data) on sheet 1, with a row for each employee the spreadsheet is tracking. The certifications are the columns.
We are using this information to link to ID Badge Printer software (Bodno Silver), where we are limited to linking columns of data to a particular textbox.
The problem lies in the fact that not everyone has every certification. The rows are peppered with blanks separating the certifications that each employee does have. While setting up the required text boxes in the badge software template, that each link to a specific column, I quickly realized that since not everyone has every certification if we used the data how it was we would have a bunch of strange looking blanks in between the listed certifications rather than a continuous list.
What I did
My solution to this (which I'm open to a better one if anyone knows of one, other than "use better software"), was to create a new sheet and array formulas that no one would use except for me and the id printer software. This sheet would have a similar data table that took the rows of data interspersed with blank cells between expiration dates, and put the matching column headers for cells that had a date in them into a continuous row of the same maximum length (eliminating the blank cells).
Essentially, this would allow me to circumvent the restrictions of the badge software and each textbox would be MatchedCert1, MatchedCert2, MatchedCert3, etc. up to the original maximum number of certifications.
Pictures are probably better than my words at explaining what I am going for:
Sheet1 (source)
Sheet2 (result)
The array formulas
I worked on this one for a while. What I thought would be a simple INDEX, MATCH, ISBLANK formula (that I could create using the appropriate relative and absolute cell linking) and then expand to the whole sheet turned into a witch hunt and me praying for forgiveness for my sins to all that may be holy. Also a lot of googling.... I realized quickly that this one may not be so simple after all.
Finally, I arrived at the following two array formulas in order to correctly show what I was going for:
First Column of training section
{=IFERROR(INDEX(Sheet1!$E$2:$P3,1,MATCH(FALSE,ISBLANK(Sheet1!E3:Q3),0)),"")}
(easy enough, right? I thought so...)
I felt good about this until I tried to think through what would be required to get the formula to be universal so that I could use it on the entire table.
I feel dirty just putting the following in public, but here goes...
Second column through last column array formula
{=IFNA(INDEX(INDIRECT(ADDRESS(ROW($E$2),(MATCH(E3,Sheet1!$2:$2,0)+1),1,1, "Sheet1")&":"&ADDRESS(ROW(E3),COLUMN($Q3),1)),1,MATCH(FALSE, ISBLANK(INDEX(INDIRECT("Sheet1!"&ADDRESS(ROW(E3),(MATCH(E3,Sheet1!$2:$2,0)+1),1)&":"&ADDRESS(ROW(E3),COLUMN($Q3),1)),0,0)), 0)),"")}
(please don't call the police...)
[ninja edit] While this array formula works for 2nd result column through the final column, it doesn't work if there's not a blank column following the result range. The actual spreadsheet has 4 different groups of certifications that run horizontally, but I was able to just add a blank column in the corresponding data from the other sheet easily enough, so I just let it go. I'd give somebody a nickle for the answer to why that's the case here too [/edit]
Results
The first array formula, and INDEX MATCH using ISBLANK is rather straightforward.
The biggest question for me here, and the thing that drove me absolutely nuts for a couple of days, is why the second array formula requires the additional INDEX function nested inside of the ISBLANK function.
While taking the function apart and experimenting I realized that if I have any INDIRECT reference inside a ISBLANK function, which is itself inside of a MATCH function, the result of the match was ALWAYS 1:
{=MATCH(FALSE,ISBLANK(INDIRECT("$E3:$Q3")), 0)}
The above ALWAYS returns 1, whereas if I put the range in explicitly, the function would work just fine. That wasn't an option for me, since I needed to dynamically return the starting position for the match using the previous cell's address.
However, adding an INDEX function (with a column and row value of 0) to encapsulate the INDIRECT function provides the correct answer. I figured this out just by trial and error.
Questions
Can someone with more knowledge please let me know what is causing this behavior?
As a broader question, given I am limited to using formulas (no VBA), I would also like to know if I'm going about this in the wrong way or if there is a much simpler way of accomplishing this without this behemoth of a formula?
I know this sheet will probably require maintenance in a year - good luck future self!
Put this in E3, Copy over and down
=IFERROR(INDEX(Sheet1!$2:$2,AGGREGATE(15,6,COLUMN(INDEX($E:$P,MATCH($C3,Sheet1!$C:$C,0),0))/(INDEX(Sheet1!$E:$P,MATCH($C3,Sheet1!$C:$C,0),0)<>""),COLUMN(A:A))),"")
As to why your formula is not working, it is too convoluted to parse. One note, unless the sheets is the variable, one should avoid INDIRECT as much as possible. INDEX can almost always be used in its place.
Both INDIRECT and ADDRESS are volatile functions. Volatile functions will re-calculate every time Excel re-calculates, leading to a lot of unnecessary computations.
Not a solution but to answer why you are seeing this behavior:
EDIT: PREVIOUS EXPLANATION WAS JUST PLAIN WRONG
This confused me so, I did a bit of investigation:
I think that your problem is actually coming from the ISBLANK function because it is intended to be used with single values, and cannot handle ranges. Any BLANKs which are returned by functions are only converted to numeric values (0), when the BLANK is returned to (or displayed on) the sheet. If the function is returning to another function, the BLANK value seems to be preserved.
EDIT: ADDING A SOLUTION WITHOUT ARRAY FORMULAS
This is probably more complex than using an array formula... but I strongly dislike them, so do all I can to remove them.
Firstly, I would add an index to your positions in the results sheet:
=IF(F$7>COUNTIFS($F3:$L3,"<>"),
"",
IF(
MINIFS(
$F$7:$L$7,$F$7:$L$7,
">" & IFNA(INDEX($F$7:$L$7,MATCH(E9,$F$2:$L$2,0)),0),
$F3:$L3,
"<>"
)=0,
"",
INDEX(
$F$2:$L$2,
MATCH(
MINIFS(
$F$7:$L$7,$F$7:$L$7,
">" & IFNA(INDEX($F$7:$L$7,MATCH(E9,$F$2:$L$2,0)),0),
$F3:$L3,
"<>"
),
$F$7:$L$7,
0
)
)
)
)
Basically, the formula looks at the cert in the previous cell, and looks for the next, minimum index, greater than that.
I have a pricelist, with currently 5 different categories of products. Each product will have to have two different prices. Depedning of the product and the type of price, the calculation will be different. Therefor I've used INDEX/MATCH to find the formula needed, from a table I created.
Below a screendump, and I wanted to attach the Excel fil, but canøt seem to work out how.
Question: HOW do I then "run" the formula I fetched? -I've tried different suggestions on using EVALUATION, but it doesn't seem to cut it? Also I've tried "Indirect' on the whole formula, without success.
I would like to avoid any VBA for this case.
Can anybody provide some insight?
You could but if I understand properly, the only thing changing in the formulas is the "muliplier" number, then it's better to lookup that number instead of the whole formula. The other method (which would use Evaluate etc) is not be considered "good practice" for a number of reasons.
EDIT:
I didn't see the 2nd varying value (since I was on the SO mobile app) but it's still not an issue since it would a target column. You could be thinking of the opposite: sometimes lookups based on multiple criteria can get complicated, but this a matter of more data, as opposed to adding criteria for the lookup.
VLookup would have been the simplest method, like G2 could have been:
=VLOOKUP(E2, $J$4:$L$8, 2, False)
...to return the second column of range J4:L8 where the first column equals E2. (Then for the next required column, same formula except with 3 instead of 2.)
Since I wasn't sure more columns could be added one day, I allowed for that by, instead of specifying "Column 2 or 3" etc, it finds the column dynamically by name. (So the multiplier/factor used in G2 will change if you change the title in G1 to the name of a different column existing in the target data chart.
For the sake of neatness as well as potential of additional columns like G & H, I moved the lookup table to a separate sheet. It can stay out of the way since you won't need to see or change it very often. (If the same chart was going to be referenced by many workbooks, you could even move it to a separate workbook and point all formulas at that, since it's always best to have one copy of identical data instead of many in different workbooks.
Also to assist with potential future changes (and just to be tidier), instead of referring to the target table range addresses (like "J4:L8" etc) I named two ranges:
the table of multiplier/factor data can be referred to by it's address, or by myMultipliers
the titles of the same table is also called myMultiplierTitles (used to match to the titles of column G & H on the original sheet.
Formula
After those changes, the lookup formula in G2 is:
=INDIRECT(VLOOKUP($E2,myMultipliers,MATCH(G$1,myMultiplierTitles,0),FALSE)&ROW())*VLOOKUP($E2,myMultipliers,MATCH(G$1,myMultiplierTitles,0)+1,FALSE)
INDIRECT returns the value of a cell that you refer to by name (text/string) as opposed to directly (as a range). For example:
=INDIRECT("A1")
returns the same as
=A1
...but with INDIRECT we can get the name from elsewhere (a cell, function or formula). So if x="A1" then =INDIRECT(x) returns the same as the 2 above examples.
Your original plan of storing the entire formula in a table as text would have worked with the help of INDIRECT and/or EVALUATE but I think this way is considered better practice partly because it facilitates easier future expansion.
The formula is longer than it would have been, but that's mostly because it's dynamically reading the field names. And size doesn't matter. :-)
I'm trying to find the most efficient way to summarise an excel sheet where only the results that are higher than 10% are included in a separate sheet.
I know how to use INDEX MATCH, and need to go one further and only INDEX MATCH when VALUE is greater than 10%'
See table, where top sheet is found in other tabs and summary sheet will populate only the description where greater than 10%.
I'm sure there is an elegant way of doing this, and I seem to over complicate my steps, breaking them down into extra columns for if, then trying to match, then return the referenced value, but ultimately I fail.
Why can't I just use Index Match (0.1,C:C,-1)? Where 0.1 is 10%. Col E, unformatted 'real' value is 0.01-0.15. Excel fails if I try =Match(0.1,E:E,-1).
This is a common mistake with MATCH. To use greater than your data set must be arranged in descending order. Likewise with less than your data set must be arranged in ascending order.
I'd suggest using the something like the following formula instead
=INDEX(A:A, AGGREGATE(15,6,ROW($A$3:$A$5)/($D$3:$D$5>0.1),ROW(1:1)))
which returns