jec*_*viz 6 excel vba worksheet-function
我想为excel创建"案例"公式来模拟选择案例行为(带有多个参数,否则可选).如果A1和A2是excel单元格,那么这就是目标:
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
Run Code Online (Sandbox Code Playgroud)
如果可以,它必须接受excel公式或vba代码,才能在获取案例之前对单元格进行操作,ig
cases({len(A1)<7, "too short"},{else,"good length"})
Run Code Online (Sandbox Code Playgroud)
如果可以,它必须接受或更多的细胞来评估,ig
如果A2 = A3 = A4 = A5 = 1且A1 = 2,A6 ="1",A7 ="2"
cases(A1!=A2|A3|A4|A5, A6}, {else,A7}) will produce "two"
Run Code Online (Sandbox Code Playgroud)
顺便说一下,| 意思是,或者!=意味着不同
有帮助吗?
我很感激.
我能写的是这个:
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
Run Code Online (Sandbox Code Playgroud)
我以这种方式调用函数
=cases(arr(A1>5, A1<5, A1=5),arr( "gt 5", "lt 5", "eq 5"))
Run Code Online (Sandbox Code Playgroud)
我无法达到目标,它只适用于第一个条件,A1> 5.
我使用for修复它,但我认为它不像你的建议那么优雅:
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
Run Code Online (Sandbox Code Playgroud)
当我调用该函数时:
=selectCases(arr(A1>5, A1<5, A1=5),arr( "gt 5", "lt 5", "eq 5"))
Run Code Online (Sandbox Code Playgroud)
有用.
谢谢大家.
下班后,最后我得到一个excel选择案例,最接近我想要的东西.
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's 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
Run Code Online (Sandbox Code Playgroud)
当A1 = 5时我打电话:
=cases(A1>5, "gt 5",A1<5, "lt 5","eq 5")
Run Code Online (Sandbox Code Playgroud)
它与"eq 5"相匹配
谢谢,这是令人兴奋的,真正的教育!
jto*_*lle 20
好吧,完全没有办法做你想要的.您不能在公式中使用除Excel语法之外的任何内容,因此"A1 = 1到9"之类的东西是不可能的.
您可以编写一个非常复杂的VBA例程,它接受字符串或其他东西并解析它们,但这实际上相当于设计和实现一个完整的小语言.并且您的"代码"不能很好地与Excel一起使用.例如,如果你打电话的话
=cases("{A1="""",""there is nothing""},{else,A1}")
Run Code Online (Sandbox Code Playgroud)
(注意转义的引号),Excel移动或复制公式时不会更新A1引用.所以让我们放弃整个"语法"选项.
然而,事实证明,你能得到多少我想到你居然要与普通Excel公式加一个很小的VBA UDF的行为.首先是UDF:
Public Function arr(ParamArray args())
arr = args
End Function
Run Code Online (Sandbox Code Playgroud)
这让我们可以从一组参数创建一个数组.由于参数可以是表达式而不仅仅是常量,我们可以从这样的公式中调用它:
=arr(A1=42, A1=99)
Run Code Online (Sandbox Code Playgroud)
并获取一个布尔值数组.
使用这个小型UDF,您现在可以使用常规公式来"选择案例".它们看起来像这样:
=CHOOSE(MATCH(TRUE, arr(A1>5, A1<5, A1=5), 0), "gt 5", "lt 5", "eq 5")
Run Code Online (Sandbox Code Playgroud)
发生了什么''arr'返回一个布尔数组,'MATCH'找到第一个TRUE的位置,'CHOOSE'返回相应的"case".
您可以通过将整个事物包装在'IFERROR'中来模拟"else"子句:
=IFERROR(CHOOSE(MATCH(TRUE, arr(A1>5, A1<5), 0), "gt 5", "lt 5"), "eq 5")
Run Code Online (Sandbox Code Playgroud)
如果这对你来说太冗长了,你总是可以编写另一个将MATCH,CHOOSE等带入其中的VBA UDF,并像这样调用它:
=cases(arr(A1>5, A1<5, A1=5), "gt 5", "lt 5", "eq 5")
Run Code Online (Sandbox Code Playgroud)
这与您提出的语法相差不远,而且更简单.
编辑:
我看到你已经提出了一个更接近你真正想要的(好的)解决方案,但我认为无论如何我都要加上这个,因为我上面关于在UDF中引入MATCH,CHOOSE等的声明使它成为了它看起来更容易.
所以,这是一个'案例'UDF:
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
Run Code Online (Sandbox Code Playgroud)
它使用一个小帮助程序,'assign':
Public Sub assign(ByRef lhs, rhs)
If IsObject(rhs) Then
Set lhs = rhs
Else
lhs = rhs
End If
End Sub
Run Code Online (Sandbox Code Playgroud)
'assign'例程可以更容易地处理用户可以使用值或范围引用调用UDF这一事实.由于我们希望我们的'case'UDF像Excel的'CHOOSE'一样工作,我们希望在必要时返回引用.
基本上,在新的'case'UDF中,我们通过索引到case值的param数组来自己做"选择"部分.我在那里打了一个错误处理程序,所以基本的东西,如案例条件结果和案例值之间的不匹配将导致返回值为#VALUE!.您可能会在实际函数中添加更多检查,例如确保条件结果是布尔值等.
不过,我很高兴你为自己找到了更好的解决方案!这很有意思.
关于'assign'的更多信息:
在回应您的评论时,这里更多的是为什么这是我答案的一部分.VBA使用不同的语法将对象分配给变量,而不是分配普通值.查看VBA帮助或查看此stackoverflow问题以及其他类似问题:关键字Set在VBA中实际执行了什么操作?
这很重要,因为当您从Excel公式调用VBA函数时,除了数字,字符串,布尔值,错误和数组之外,参数还可以是Range类型的对象.(请参阅从工作表调用的Excel VBA UDF是否可以传递除"Range"以外的任何Excel VBA对象模型类的实例?)
范围引用是您使用Excel语法(如A1:Q42)描述的内容.将一个Excel UDF作为参数传递给它时,它将显示为Range对象.如果要从UDF返回Range对象,则必须使用VBA"Set"关键字显式执行.如果您不使用'Set',Excel将取代Range中包含的值并返回该值.大多数情况下这并不重要,但有时您需要实际范围,例如当您有一个必须评估范围的命名公式时,因为它被用作验证列表的源.
| 归档时间: |
|
| 查看次数: |
17527 次 |
| 最近记录: |