I have a VBA function that returns an array to be displayed in Excel. The array's first two columns contain ID's that don't need to be displayed.
Is there any way to modify the Excel formula to skip the first two columns, without going back to create a VBA helper to strip off the columns?
The formula looks like this, where the brackets let the array be displayed across a span of cells:
{=GetCustomers($a$1)}
The closest thing Excel has to built-in array manipulation is the 'INDEX' function. In your case, if the array returned by your 'GetCustomers' routine is a single row, and if you know how long it is (which I guess you do since you're putting it into the sheet), you can get what you want by doing something like this:
=INDEX(GetCustomers($A$1),{3,4,5})
So say GetCustomers() returned the array {1,2,"a","b","c"}, the above would just give back {"a","b","c"}.
There are various ways to save yourself having to type out your array of indices, though. For example,
=COLUMN(C1:E1)
will return {3,4,5}, and you can use that instead:
=INDEX(GetCustomers($A$1),COLUMN(C1:E1))
This trick doesn't work with a true 2-D array, though. 'INDEX' will return a whole row or column if you pass in a zero in the right place, but I don't know how to make it return a 2-D subset. EDIT: You can do it, but it's cumbersome. Say your array is 2x5, and you want the last three columns. You could use:
=INDEX(GetCustomers($A$1), {1,1,1;2,2,2}, {3,4,5;3,4,5})
(FURTHER EDIT: chris neilsen provides a nice way to compute those arrays in his answer.)
Charles Williams has a link on his website that explains more about using arrays like this here:
http://www.decisionmodels.com/optspeedj.htm
He posted that in response to this question I asked:
Is there any documentation of the behavior of built-in Excel functions called with array arguments?
Personally, I use VBA helper functions for things like this. With the right library routines, you can do something like:
=subseq(GetCustomers($A$1),3,3)
in the 1-D case, or:
=hstack(subseq(asCols(GetCustomers($A$1)),3,3))
in the 2-D case, and it's much more clear.
simplest solution is to just hide the first two columns
another may be to use OFFSET to resize the returned array
syntax is
OFFSET(reference,rows,cols,height,width)
I suggest modifying the 'GetCustomers' function to include an optional Boolean variable to tell the function to return all the columns, or just the single column. That would be the cleanest solution, instead of trying to handle it on the formula side.
Public Function GetCustomers(rng as Range, Optional stripColumns as Boolean = False) as Variant()
If stripColumns Then 'Resize array to meet your needs
Else 'return full sized array
End If
End Function
You can use the INDEX function to extract items from the return array
- formula is in an range starting at cell B2
{=INDEX(getcustomers($A$1),ROW()-ROW($B$2)+1,COLUMN()-COLUMN($B$2)+3)}
Related
I'm trying to create a google sheets function where I use a array function [like UNIQUE() or FILTER()]but the array is returned into one cell and I can specify the location of the value I'm trying to obtain.
I think its analogous to a List in R where you have a list full of a number of string characters and you can return the one you want by specifying where it falls in the list.
Below is a sample of the problem I'm trying to solve.
Functions are as follows:
In cell B1: =UNIQUE(A1:A12)
In cell E1: =CHOOSE(C1, $B$1, $B$2, $B$3, $B$4)
I'd like all of this to happen in one cell. Is that possible? I was thinking maybe Lambda functions would be helpful here but I couldn't understand it well enough to use it in this scenario.
I have tried without success a bunch of combinations of the following functions: Lambda functions, Index(), Choose()
Thanks a ton!
I'm not sure why you're having trouble with INDEX in this situation. Given the list in A1:A12, =INDEX(UNIQUE(A1:A12),n) where n is 1-4 will give you the item at that position in the array?
For multiple ns use MAP to supply the row values to INDEX:
=map({n1;n2...},lambda(n,index(unique(A1:A12),n)))
Try put this into E1 in your sample sheet.
This formula do exactly what you have requested.
Pack all your formulas (UNIQUE(A1:A),CHOOSE(C1)) up into one cell with the help of LAMBDA and INDEX.
The output will change according to the numbers you enter in C1:C4.
=LAMBDA(ARRAY,INDEXES,
LAMBDA(VAL_1,VAL_2,VAL_3,VAL_4,
BYROW(INDEXES,LAMBDA(ROW,
CHOOSE(ROW,VAL_1,VAL_2,VAL_3,VAL_4)
))
)(INDEX(ARRAY,1),INDEX(ARRAY,2),INDEX(ARRAY,3),INDEX(ARRAY,4))
)(UNIQUE(A1:A),$C$1:$C$4)
I have a list of values that I would like to match against the combination of multiple ranges.
So, for example, my ranges are A1:A100 and B1:B100.
Instead of concatenating A with B in a new column C, i.e.
CONCAT(A1,B1)...CONCAT(A100,B100)
and then matching my value against that new column - I would like to do something like this:
MATCH(value,CONCATENATE(A1:B100),0)
And copy this down a column near my list of values.
I have a feeling this can be done with some sort of array formula...
Yes as an array formula:
=MATCH(value,$A$1:$A$100 & $B$1:$B$100,0)
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when exiting edit mode.
Though they may seem similar in approach they are not. CONCATENATE will return a string not an array to the MATCH with all 200 values in one long string. Where the above will return 100 values, each row concatenated, as an array which can be used to search.
One further note, If performance becomes a issue, Array formulas are inherently slower, adding the helper column and using a regular MATCH will improve the responsiveness.
This should work, basically you just need to concatenate it yourself using &
=MATCH(D1,A1:A10&B1:B10,0)
D1 is the value you're trying to look for.
This is an array, so remember to hit Ctrl+Shift+Enter when you input it.
I need to pass a multiple criteria list (a constant array) via cell reference rather than hard-typing it into my formula.
So, instead of this:
=SUM(SUMIFS(sum_range,criteria_range,{"red","blue"}))
But I would need to use this:
=SUM(SUMIFS(sum_range,criteria_range,$A1)) where $A1 is {"red","blue"}
I understand that one can use a range of cells to pass an array but I really need my condition to come from a single cell.
It seems that passing a constant array via cell reference only passes the first element to the formula (i.e. only "red" is used as a condition) and all the working examples I could find of this (here or here) are hard-typing the condition into the formula.
Any luck anybody ?
EDIT: I should add that my data set includes blank rows so it is not contiguous and in general, I'm looking for a not too convoluted solution that will work most of the time and with as little restrictions and caveats as possible.
Change the "Array" in A1 to a comma delineated list:
blue,purple
No quotes or {}
Change the SUM to SUMPRODUCT and use this as the criteria:
TRIM(MID(SUBSTITUTE(A1,",",REPT(" ",99)),(ROW(INDEX(AAA:AAA,1):INDEX(AAA:AAA,LEN(A1)-LEN(SUBSTITUTE(A1,",",""))+1))-1)*99+1,99))
The $20 should be placed at the max number of choices possible. I just used it here as a placeholder, it can be more without problem but not less or it will skip any more than that.
Based on the formula you provided.
=SUMPRODUCT(SUMIFS(W$12:W$448,$I$12:$I$448,$I474,$J$12:$J$448,$J474,$K$12:$K$448,TRIM(MID(SUBSTITUTE(A1,",",REPT(" ",99)),(ROW(INDEX(AAA:AAA,1):INDEX(AAA:AAA,LEN(A1)-LEN(SUBSTITUTE(A1,",",""))+1))-1)*99+1,99))))
With cell A1 containing {"red","blue"} I then setup a named range Condition to which I assigned =EVALUATE($A1) and now I can pass my condition like so:
=SUM(SUMIFS(W$12:W$448,$I$12:$I$448,$I474,$J$12:$J$448,$J474,$K$12:$K$448,Condition))
I want to use COUNTIF function to evaluate how many items out of 2,0,0,5 are greater than 2? In Countif function, first argument is range and second is criteria. I have tried the below formula. Even tried using Ctrl+Shift+Enter at the end to evaluate. But doesn't seem to work.
=COUNTIF({"2","0","0","5"},">2")
COUNTIF doesn't accept array constants (as far as I know). Try this:
=SUMPRODUCT(--({2,0,0,5}>2))
You could also create a countif-style formula like this (the combination ctrl+shift+enter):
=COUNT(IF({2,0,0,5}>2,1,""))
Recommended reading:
Array vs Range
Some functions like Offset, SumIf, CountIf, SumIfs, and CountIfs are designed to operate only on (multi-cell) range objects. Sum, SumProduct, Frequency, Linest, lookup functions, etc. take both range and array objects.
Array means: {2,0,0,5}
Range means:
To use countif, you have to use range in cells, defining the array in the formula on the go will not work.
=COUNTIF(A1:A4,">"&2)
I know this thread is a few years old, but I ended up here with a similar problem (how to use arrays, not ranges, with countif).
Although my end goal was a little different (I wanted to find items common to two arrays), I figure the workaround I came up with might be useful for others: I ended up using the "match" function coupled with "isnumber". The formula looked like this:
=isnumber(match({a},{b},0))
this will return an array of true/false which corresponds to the values in {a} that are also in {b}. In case it wasn't clear, {a} and {b} are arrays...
On one sheet in my file I have a number of arrays defined as named ranges. One another sheet I'd like to use a drop down, or something similar to select the name of one of the named range and have the data/contents of that named range populate a range on the second sheet. Is this possible WITHOUT VBA? Is there an array formula that will do this?
One, not entirely elegant, method that I've thought of is using the index function and copy this within a range of cells equivalent in size to the size of the largest named range. Something like:
=INDEX(range_1,ROW(),COLUMN())
This requires me to be able to pass the name of a named range into a function though. Is this possible?
Answers to either or both of these questions would be greatly appreciated.
Without that, the only other way I can think to do this is using a brute force, offset look up, which I'd prefer not to do.
Thanks for your help.
Indirect might do what you want it to.
In Sheet1 I created 3 named ranges:
Then in Sheet2, I
1) Put these names in Column A
2) Used a data validation list linked to column A to place a name in a cell (C2)
3) Used the array formula {=INDIRECT(C2)} (accepted with Ctrl+Shift+Enter) in the cells that I wanted to hold the array (C4:E5)
When C2 is changed via the drop-down, the array is automatically changed: