Sadly, the use of the volatile INDIRECT
and OFFSET
are almost ubiquitously recommended in such cases on the various Excel sites around, even though there exists a perfectly good, minimally volatile (in fact, volatile "at workbook open" only, as I understand) set-up using INDEX
.
To determine the last non-empty row in a column, column A say, it will be useful to know the datatype of the entries within that column, and also whether there are any null strings ("") present.
Although there are set-ups available which will work whatever the datatype of the entries in question, they are necessarily of a type such that they must process each element within the range passed to them. As such - and particularly if the range over which it is necessary to calculate is quite large - they can be extremely resource-heavy (the second suggestion by kyle being a good example, having to process more than a million cells, irrespective of whether the last non-empty cell is in row 1 or row 1048576).
It is also worthwhile storing the value of the last non-empty row as a Defined Name, LRow say.
The possible definitions for LRow are then as follows:
1) If there are no null strings and all entries are non-numerical, you can define LRow as:
=MATCH("Ω",A:A)
2) If there are no null strings and all entries are numerical, you can define LRow as:
=MATCH(9.9E+307,A:A)
3) If there are no null strings and entries are of a mixed datatype, i.e. some numerical, some non-numerical, you can define LRow as:
=MAX(MATCH("Ω",A:A),MATCH(9.9E+307,A:A))
If there are null strings within the range then the solutions become necessarily more complex, and it is no longer possible to avoid a construction in which each cell within the array is processed individually. As such, the best we can do is to minimize the range which we pass to be processed.
Hence, we have:
4) If there are null strings, you can define LRow as:
=MATCH(1,0/(LEN(A1:INDEX(A:A,MAX(MATCH("Ω",A:A),MATCH(9.9E+307,A:A))))>0))
(You could of course make this even more efficient if the datatype is consistently numerical or non-numerical, as above.)
which requires array-entry (CSE) and which, in general, will vastly reduce the range being processed, especially compared to something such as:
=MATCH(1,0/(LEN(A:A)>0))
which is disastrous in terms of efficiency.
Note that the additional functions within the former are of very little detriment: it is far more important to reduce the number of cells being processed than to worry about an additional function call or two.
You can now use this within an INDEX
construction to dynamically define your range. For example:
=A1:INDEX(A:A,LRow)
which, as mentioned, is barely volatile at all.
Regards
Best Answer
What your formula does:
is count 1 if the cell A27 is
LBNL
, orLawrence Berkeley
orLBL
orLawrence Lab*
(the*
acting as a wildcard here).So, if you have a cell being
LBNL
, you'll get 1 as result. HavingDr. LBNL
will result in 0.If you want to get a count of
1
if the cell contains at least 1LBNL
, then you need to use wildcards on both sides of the text, namely:You can make a named range and put it there instead, but this will become an array formula which will only work with Ctrl+Shift+Enter:
Now, you can use
SUMPRODUCT
to avoid having to use CSE to use this formula:If however you have a cell containing
LBNL LBNL
and want the result to be2
, that's yet another matter, becauseCOUNTIF
's job is completed once it found what it was looking for in a cell and will return1
.In that case, I would suggest counting each cell to be checked (because the above function can be used to look into whole columns):
[Notice now that you need to drop the asterisks because of how
SUBSTITUTE
works.]