Excel Select Case?

I want to create a “cases” formula for Excel to simulate case selection behavior (with a few arguments and not yet necessary). If A1 and A2 are Excel cells, this is the goal:

A1 Case: A2 Formula: A2 Result 5 cases({A1>5,"greather than 5"}, {A1<5, "less than 5"},{else,"equal to 5"}) equal to 5 Hi cases({A1="","there is nothing"},{else,A1}) Hi 1024 cases({5<A1<=10,10},{11<=A1<100,100},{A1>100,1000}) 1000 12 cases({A1=1 to 9, "digit"}, {A1=11|22|33|44|55|66|77|88|99, "11 multiple"}) (empty) 60 cases({A1=1 to 49|51 to 99,"not 50"}) not 50 

If possible, he should accept Excel formulas or VBA code to do the operation on the cell before taking the case, ig

 cases({len(A1)<7, "too short"},{else,"good length"}) 

If possible, he should take or more cells to evaluate, for example,

if A2 = A3 = A4 = A5 = 1 and A1 = 2, A6 = "one", A7 = "two"

 cases(A1!=A2|A3|A4|A5, A6}, {else,A7}) will produce "two" 

By the way | means or ,! = means different

Any help?




I'm glad.

I could write the following:

 Public Function arr(ParamArray args()) 'Your function, thanks arr = args End Function Public Function cases(arg, arg2) 'I don't know how to do it better With Application.WorksheetFunction cases = .Choose(.Match(True, arg, 0), arg2) End With End Function 

I call the function this way

 =cases(arr(A1>5, A1<5, A1=5),arr( "gt 5", "lt 5", "eq 5")) 

And I can’t get the target, it just works for the first condition, A1> 5.

I fixed this using for, but I think it is not elegant as your suggestion:

 Function selectCases(cases, actions) For i = 1 To UBound(cases) If cases(i) = True Then selectCases = actions(i) Exit Function End If Next End Function 



When I call the function:

 =selectCases(arr(A1>5, A1<5, A1=5),arr( "gt 5", "lt 5", "eq 5")) 

It is working.

Thanks for all.




After a little work, finally I get an excellent case, closer to what I want first.

 Function cases(ParamArray casesList()) 'Check all arguments in list by pairs (case, action), 'case is 2n element 'action is 2n+1 element 'if 2n element is not a test or case, then it like the "otherwise action" For i = 0 To UBound(casesList) Step 2 'if case checks If casesList(i) = True Then 'then take action cases = casesList(i + 1) Exit Function ElseIf casesList(i) <> False Then 'when the element is not a case (a boolean value), 'then take the element. 'It works like else sentence cases = casesList(i) Exit Function End If Next End Function 

When A1 = 5 and I call:

 =cases(A1>5, "gt 5",A1<5, "lt 5","eq 5") 

This can be read as follows: if A1 is greater than 5, select "gt 5", but if A1 is less than 5, select "lt 5", otherwise select "eq 5". After launch, it matches "eq 5"

Thank you, it was fascinating and truly informative!

+6
vba excel worksheet-function
Jan 17 '11 at 18:15
source share
1 answer

OK, there is no way to do what you want. You cannot use anything but the Excel syntax inside the formula, so things like "A1 = 1 to 9" are simply not possible.

You can write a rather complicated VBA procedure that took strings or something else and analyzed them, but it really comes down to developing and implementing a complete little language. And your "code" will not work well with Excel. For example, if you called something like

 =cases("{A1="""",""there is nothing""},{else,A1}") 

(note the escaped quotes), Excel will not update your A1 link when you move it or copy the formula. Therefore, discard the entire syntax parameter.

However, it turns out that you can get most of the behavior that I think you really need with the usual Excel formulas plus one tiny VBA UDF. UDF first:

 Public Function arr(ParamArray args()) arr = args End Function 

This allows us to create an array from a set of arguments. Since arguments can be expressions, not just constants, we can call this from the formula as follows:

 =arr(A1=42, A1=99) 

and return an array of booleans.

With this little UDF, you can now use regular formulas to "select cases." They would look like this:

 =CHOOSE(MATCH(TRUE, arr(A1>5, A1<5, A1=5), 0), "gt 5", "lt 5", "eq 5") 

What happens is that 'arr' returns a boolean array, "MATCH" finds the position of the first TRUE, and "CHOOSE" returns the corresponding "case".

You can emulate the else clause by wrapping it all in IFERROR:

 =IFERROR(CHOOSE(MATCH(TRUE, arr(A1>5, A1<5), 0), "gt 5", "lt 5"), "eq 5") 

If this is too much for you, you can always write another VBA UDF that will result in MATCH, CHOOSE, etc. inside and will call it like this:

 =cases(arr(A1>5, A1<5, A1=5), "gt 5", "lt 5", "eq 5") 

This is not far from your suggested syntax and much, much simpler.

EDIT:

I see that you have already come up with a (good) solution that is closer to what you really want, but I thought I'd add this anyway, since my expression above is about casting MATCH, CHOOSE, etc. inside UDF made it look easier than it really is.

So, here are the “UDF” cases:

 Public Function cases(caseCondResults, ParamArray caseValues()) On Error GoTo EH Dim resOfMatch resOfMatch = Application.Match(True, caseCondResults, 0) If IsError(resOfMatch) Then cases = resOfMatch Else Call assign(cases, caseValues(LBound(caseValues) + resOfMatch - 1)) End If Exit Function EH: cases = CVErr(xlValue) End Function 

It uses a small helper procedure, 'assign':

 Public Sub assign(ByRef lhs, rhs) If IsObject(rhs) Then Set lhs = rhs Else lhs = rhs End If End Sub 

The assign procedure simply simplifies the consideration of the fact that users can invoke UDFs with any values ​​or range references. Since we want the UDF of our “cases” to work like Excel “CHOOSE”, we would like to return links if necessary.

Basically, in the new UDF “cases”, we ourselves make a “choice” by indexing case values ​​into an array of parameters. I removed the error handler there, so basic things, such as a mismatch between the results of the case condition and the case values, will result in the return value #VALUE !. You would probably add more checks to the real function, for example, to make sure that the results of the condition were logical, etc.

I am glad that you have reached an even better solution for yourself! That was interesting.

MORE ABOUT 'assign':

In response to your comment, here is more about why this is part of my answer. VBA uses a different syntax to assign an object to a variable than to assign a simple value. Look at the VBA help or look at this stackoverflow question, and others will like: What does the Set keyword really do in VBA?

This matters because when you call a VBA function from an Excel formula, the parameters can be objects of type Range, in addition to numbers, strings, booleans, errors, and arrays. (See Can Excel VBA UDF called from a worksheet ever pass an instance of any Excel VBA object model class other than "Range"? )

Range references are what you describe using Excel syntax such as A1: Q42. When you pass one to Excel UDF as a parameter, it displays as a Range object. If you want to return a Range object from UDF, you need to do this explicitly using the VBA keyword “Install”. If you do not use Install, Excel will instead accept the value contained within the range and return it. In most cases, this does not matter, but sometimes you need the actual range, for example, when you have a named formula that needs to be evaluated in the range, because it is used as the source for the check list.

+19
Jan 18 '11 at 1:30
source share



All Articles