I created this worksheet function and it works perfectly.
=LARGE({1;2;3;4;5;6;7;8;9;10;11;12;13;14;0;16;0;0;0;20;21;0;0},1)
The problem is how I created it. I started out with the function below which, unfortunately, does not work. It returns 0 instead of 21. That is unfortunate because it's precisely this function that I need.
=LARGE(ISBLANK(R$1:R23)*ROW(R$1:R23),1)
I converted the function I want to the function that works by selecting ISBLANK(R$1:R23)*ROW(R$1:R23) in the formula bar and pressing F9. Of course, this action merely displays the array specified by the formula. Therefore the working function and the not working function are technically identical. If you can't tell me how that can be then please try telling me why it is so.
Of course, I tried all the remedies that appeared "obvious". I tried entering the formula as an array formula (no need in Excel 365). I added -- before the ISBLANK function and tried that with the function in parentheses. All to no avail.
BTW, my purpose is to use the number of the blank sheet row above the cell with the formula in an OFFSET function to return a value from another column in that row. Imagine a block of cells with a title and wanting to reference the title row from any cell in the block, where the title row is identifiable because it has blank cells in the columns where the block has data.
Related
In order to do some calculations on averages and differences of values in columns, I've defined a name, based on a range, but it seems to be completely going berserk:
I have a cell (D13), defined as Header_First _Answer, which contains the title of the column, and I have a value (currently being 69), which contains the number of entries, called Total_Count.
I've defined the entries of that column as another name: "All_First_Answered_Dates", defined as =OFFSET(Header_First_Answer;1;0):OFFSET(Header_First_Answer;Total_Count;0) (start by the first entry under Header_First_Answer, take up to 69 entries, and define a range out of this).
In cell G5, I'm using that name in order to do some calculations (calculating averages), but this seems not to work (there is a #Value error).
After second comment from Rory: G5 formula and first formula evaluation result:
Formula:
=AVERAGE(IF(ISBLANK(All_First_Answered_Dates);TODAY();All_First_Answered_Dates) - All_Start_Dates)
First evaluation result:
=AVERAGE(IF(ISBLANK(#Value!);TODAY();All_First_Answered_Dates) - All_Start_Dates)
Hence, my conclusion:
After some checking I've found out that this is due to the name "All_First_Answered_Dates", which seems to be interpreted one time too many (or how do I explain this):
In different cells, I've entered the formula =OFFSET(Header_First_Answer;1;0):OFFSET(Header_First_Answer;Total_Count;0) (which is exactly the meaning of "All_First_Answered_Dates"), and every time, using the Evaluate Formula feature, I see that the last but one result is correct: $D$14:$D$82. However, after that, another evaluation is done, turning this value into 43283 (in case the formula is entered in "J14"), 43300 (in case the formula is entered in "J15"), ..., and in case I enter this formula in a cell with row number lower than 14, I have the error value #Value (which explains the wrong result in cell G5).
If I simply put the formula =$D$14:$D$82 in any of the mentioned cells, then the content of some cells in column D are shown (which are dates, not values like 43283 or 43300).
It appears that declaring a range as =x:y, where x and y are formula results, is not working.
Does anybody know how I can define a range as a formula, which I can then use in order to define in a name?
I can imagine my explanation being quite complicated without an image, hence the attached screenshot. In there:
In cell J13, there is the formula =OFFSET(Header_First_Answer;1;0):OFFSET(Header_First_Answer;Total_Count;0).
In cell J14, there is the same formula.
In cell K14, there is the formula =$D$14:$D$82.
For completion purposes, hereby a screenshot of the name manager, containing both mentioned names (the ones, selected in the name manager):
Edit after first comment:
The idea behind the range is the following:
1. Take the first row under Header_First_Answer, do not take any other column : OFFSET(Header_First_Answer;1;0)
2. Take the Total_Count's row under Header_First_Answer, do not take any other column : OFFSET(Header_First_Answer;Total_Count;0)
3. Define a range, based on those two cells, by putting a semicolon between them.
I was not aware of the height and width features of the Offset() worksheet function. I've implemented them, which makes the formulas much easier.
Unfortunately the problem still persists.
Thanks in advance
Dominique
I've just found the answer of what was going wrong:
The formula was meant to be an array formula. Something went wrong and while trying to debug, I accidently re-formatted the formula into a normal formula (I must have pressed "ENTER" instead of "Ctrl" + "Shift" + "ENTER") at some point.
I have re-applied array formula (using "Ctrl" + "Shift" + "ENTER"), getting a formula like:
{=AVERAGE(IF(ISBLANK(All_First_Answered_Dates);TODAY();All_First_Answered_Dates) - All_Start_Dates)}
(mind the braces {, })
Now everything is working fine.
I'm very new to VBA, yet I still find myself writing a UDF for excel and part of that process requires that a value be pulled from another sheet that is open in the same workbook. I don't know what I'm doing obviously, but I'm hoping someone else can point me in the right direction.
A sheet called "VIAL TYPES" has the data that I need in the 7th column.
For the purpose of this question, I would just like to print the value of VLookup in cell G9.
To run the function, I would manually write in the VialType in an adjacent cell. I expect the Vlookup function to recognize the type entered into cell (=VTEST(cellIwrotethevialtypein)), find it's match in the "VIAL TYPES" sheet and then print the value in the 7th column back in the active sheet. Basically, I want it to do exactly what VLOOKUP does, I just need this to work in vba so that I can execute additional things with the value.
I get #Value! in the cell now.
Function VTEST(VialType As String)
ActiveWorkbook.ActiveSheet.Range("G9").Value = Application.WorksheetFunction.VLookup(VialType, ActiveWorkbook.Worksheets("VIAL TYPES").Range("A1:A309"), 7, False)
End Function
I am using excel to create data sets that are used in a vba application later. I am using this formula:
=INDEX(BaseData!$L$2:$L$10000;MATCH(DataSet!D5&DataSet!E5&DataSet!K5;INDEX(BaseData!$B$2:$B$10000&BaseData!$C$2:$C$10000&BaseData!$D$2:$D$10000;0);0))
usually with a range from f.ex.: A2 - A10000, because my data can be differently long and often vary in data selection.
However, this slows my excel extremely down. I switched to manual calculations, but then, when activating automatic again, my excel instance takes extremely long and often crashes.
I also tried to past some data, but when creating a new dataset, I have to pull the formula down again and sometimes through this errors occur in my data set.
Any suggestions what I can do to make the INDEX-MATCH formulas more performant?
I appreciate your replies!
UPDATE
I guess a lot of performance goes away because index-match does not select the exact range, but also counts in blank rows. How to get the exactl range with index match automatically?
As I mention in my comment above, as long as this is a 'regular' formula and not an Array Formula, you may find success simply replacing "A1:A10000" with "A:A". However barring that, you can create a cell which will calculate reference the number of rows of data which you have, and then use that cell to indirectly reference the complete column with data in it.
CALCULATING YOUR DESIRED RANGE
For the following example to work, I assume that: Column A includes an index key in the form of numbers only; Column A includes no numbers in the header and above; and that the index rows are continuous, with no breaks. Start with the following formula:
=COUNT(A:A)
If my assumptions above hold, then this will return the number of data elements in your table. Once we know where this data starts, we can use this COUNT to determine where it ends. Assume your header is in row 2. (I like to include the header so that if you insert a row beneath the header, Excel picks up that you want to include the new row in your formulas).With that in mind, this formula will create the Excel-style reference which finds the last cell in column A which has data in it:
=ADDRESS(ROW(A2)+1+COUNT(A:A),COLUMN(A2),1,1)
Assuming 50 rows of data [which start at row 3, below the header], and all other assumptions above, this formula will return the text result "$A$53".
If you wanted to do the same thing, but instead return the full range in Column A where data exists (from the header to row 53), you could do as follows:
=ADDRESS(ROW(A2),COLUMN(A2),1,1)&":"&ADDRESS(ROW(A2)+1+COUNT(A:A),COLUMN(A2),1,1)
This returns the text string result "$A$2:$A$53", which is a reference to the full index of unique ID values. It will automatically move around as you would generally expect if you insert any rows or columns. Now assume for your INDEX that you want to pull the same data, but for column B, instead. The formula will be exactly the same, except that where I have "COLUMN(A2)" above, replace with "COLUMN(B2)".
REFERENCING YOUR CALCULATED RANGE
So now you have the address of your proper, limited columns - but how do you actually reference those areas in a formula? By using the INDIRECT function. INDIRECT says "Evaluate some specific criteria. It will create a cell reference. Now look at that cell reference." In its simplest form, this could look like this:
=INDIRECT(A1)
Assume that A1 holds the value "B5". Indirect will pick up the value "B5", and instead of displaying "B5", it will go to B5, and pick up the value there. So to use this with the above, wrap the whole thing in the INDIRECT function. Instead of picking up the text string "$A$1:$A$53", it will actually now reference that range properly. Like so:
=INDIRECT(ADDRESS(ROW(A2),COLUMN(A2),1,1)&":"&ADDRESS(ROW(A2)+1+COUNT(A:A),COLUMN(A2),1,1))
USING A NAMED RANGE
But that is a very long formula to have, and you won't want to use it within a specific cell for a simple INDEX/MATCH. Instead of entering these formulas in cells (although you could), I recommend you go to the Formula Ribbon -> Name Manager -> New Name. Call the name for the index of A "ID_COLUMN". Call the name for the index of "B_COLUMN" (or something more specific).
FINAL FORMULA
Now, if you wanted to make an INDEX/MATCH of your table, which automatically grows/shrinks as you change the data, your formula would look like this [this would, for example, pick the row from column B where column A has the number 100]:
=INDEX(ID_COLUMN,MATCH(100, B_COLUMN, 0))
This links to question 12299700 - I want to understand why SEARCH returns #Value when used alone but works when embedded into LOOKUP, and how I can make it work alone:
In Cell A1 I have a string of text: "This is some sample text"
In Cells D1:D4 I have words: "text, sample1, sample2, string" (all in separate cells)
I want to see if my string contains any of the words in my range - I don't need the matching word/s returned.
Using the Search function in any empty cell in Row 1 =SEARCH($D$1:$D$4,A1), returns 22. Good!
Using this in any other row returns #VALUE. Why?
If I keep my formula in Row 1, but move my range of words down to D2:D5, I get #Value. Why?
How can I make SEARCH work for my cell and ranges, in any cell?
(From the answer to question 12299700 I know I can use this formula to return the matched text, in any cell of the spreadsheet: =LOOKUP(2^15,SEARCH($D$1:$D$4,A1),$D$1:$D$4) - this includes a term that gives #VALUE on its own ... intriguing).
First question asked on Stackoverflow - feedback appreciated.
The function SEARCH returns #VALUE if the searched string was not found within the text. The function SEARCH expect only one searched string. It is not a array function itself. So if it gets a range as searched string, it uses only one of these range values as searched string. Which one it is, depends on the position of the formula.
Within LOOKUP the case is completely different. LOOKUP is an array formula itself. It gets the SEARCH($D$1:$D$4,$A$1) as { SEARCH($D$1,$A$1), SEARCH($D$2,$A$1), SEARCH($D$3,$A$1), SEARCH($D$4,$A$1) } which results in a array like { #VALUE, 21, #VALUE, 21 } depending of if SEARCH finds the string or not. That LOOKUP even works with such an array is strange. Normally it needs a sorted array. But it works and gets the last value which is lower or equal than the searched value.
If you need to use SEARCH like an array formula outside a native array formula, then you have to create this array context by entering the formula with [CTRL]+[SHIFT]+[ENTER] instead of only [ENTER]. The formula gets then curly braces around it.
In my example I have created such a formula in Cell E10.
If you are interested in how formulas work, you should often click fx and look how the single parameters comes through. And you should often use Evaluate Formula on the Formulas tab, in the Formula Auditing group.
What happens is that SEARCH is being used in an array form and is outputting in a linear form (non-array).
So, what happens in row 1 is that you're actually doing:
=SEARCH($D$1,A1)
Because evaluating a linear formula with an array tends to take the value from the array in the same row/column depending on the situation. So that means the above is looking for text in A1 which can be found.
On the second row, you will get:
=SEARCH($D$2,A1)
Which means it is searching for sample1 from A1 and since it cannot be found, you get #VALUE!.
To evaluate an array formula as an array, you will have to use Ctrl+Shift+Enter instead of pushing Enter after typing in the formula. Now the problem is that the formula above will return the same thing if you use only 1 cell...
If you want to see if your string contains any of the words in your range (and it's not important to know what word was found), then you will have to use another function along with SEARCH, for example, SUM and ISNUMBER and evaluating it as an array formula:
=SUM(ISNUMBER(SEARCH($D$1:$D$4,A1)))
And if you get a number above 0, you know there's at least 1 word in the text. Maybe to make the output more explicit:
=IF(SUM(ISNUMBER(SEARCH($D$1:$D$4,A1)))>0, "Word(s) found!", "No words found...")
If you want to know what word was found, you will have to use it as a normal formula and drag it down:
The reason why it works in VLOOKUP is that this function actually expects an array as the second parameter and since SEARCH is returning an array, well, that works out just well.
Also, you can view how functions work by clicking on the cell with the function, then do to 'Formulas' in the menu bar and clicking on 'Evaluate formula':
From there you can see if something is being evaluated as a linear or array formula and see how cell references are being substituted with the actual values.
I'm writing an IF function, and one of the [If_value_False] slots needs to be a random Function.
It works fine, but once the random formula is posted, the cell dosn't randomize, the IF function behaves as if whatever is in the value true has to be text, not a forumla.
Here's the function I've got:
=IF(ISBLANK(A2),"","=rand()")
If A2 is blank, this function should leave everything blank too whenever it's placed
If A2 is not blank, it should add a random function. That works up to there. The cell dosn't follow the =RAND() function.
How can I fix this?
Remove the quotes around the RAND() function
=IF(ISBLANK(A2),"",RAND())
I think your formula works as expected - it sets the displayed contents of the cell to the text "=rand()". If you want to set it to an actual function, I believe you have to do it from VBA using the notation
ActiveCell.Formula = "=rand()".