EXCEL SUM不适用于ARRAY中的UDF

时间:2017-04-18 20:17:36

标签: excel excel-vba vba

在我的wooksheet中我有单元格:A1 = 1和A2 = 2

此公式当然适用于工作表的单元格:

    =SUM(A1:A2) [correctly giving *3*]

但是我确实有这样的值:A1:1½和A2 =2½ 但是此数组(CSE)公式不起作用:

    {=SUM(myUserDefinedFkt(A1:A2))} [giving *#VALUE*, should have been *4*]

其中myUserDefinedFkt可以像(仅示例)一样简单:

    public function myUserDefinedFkt(value) as double
        if instr(1, value, "½" , 1)>0 then value = replace(value, "½", ".5")
        myUserDefinedFkt = value
    end function

我认为使用数组公式是正确的,但是如何?

EDIT。我改变了我的功能,两个单元格值更加精确!

4 个答案:

答案 0 :(得分:0)

使用以下用户定义函数= UDFSumstring(A1:B10)
不需要数组公式输入
这个UDF

  • 将所有“½”替换为“.5”
  • 将字符串转换为其值
  • 总结结果
  • 对于范围(A1:B10)而不仅仅是(A1:A2)
  

Function UDFSumstring(ByVal cell_range As Range) As Double    
>         Dim i As Long, j As Long, total As Double
>         Dim varray As Variant, sv As Double
>         varray = cell_range.Value>       
>         For i = 1 To UBound(varray, 1)
>             For j = 1 To UBound(varray, 2)
>                 If InStr(1, varray(i, j), "½") > 0 Then
>                 sv = Val(WorksheetFunction.Substitute(varray(i, j), "½", ".5"))
>                 Else
>                 sv = Val(varray(i, j))
>                 End If
>             total = total + sv
>             Next
>         Next
>         
>         UDFSumstring = total
>         
>         End Function

答案 1 :(得分:0)

您可以这样做,以便在公式中调用函数两次(或每次需要多次)。

让你的函数返回一个值:

 Public Function myUserDefinedFkt(value) As Double
     If InStr(1, value, "1/2") > 0 Then
        myUserDefinedFkt = CDbl(Left(value, Len(value) - 4) & ".5")
     Else
        myUserDefinedFkt = CDbl(value)
     End If
 End Function

然后在工作表中写下这样的公式:

=myuserdefinedfkt(A1)+myuserdefinedfkt(B1)

enter image description here

答案 2 :(得分:0)

UDF是否可以返回数组,因此可以用作数组公式取决于UDF。即使Excels本机函数 所有也可用于数组上下文。

所以首先我们必须有一个可以返回数组的UDF。在User defined function in VBA not "array-firendly"中,我为arrayFriendlyUDF的原型提供了一种方法。

使用这个我们也可以解决这个问题的问题:

UDF:

Public Function arrayFriendlyUDF(vParam As Variant) As Variant
 'function which can get variant parameter vParam
 'either a single value or a range or an array literal
 'will return a single value or an array of results
 'it will only accept double values or strings as single value, in range or in array literal

 Dim adParam As Variant, dParam As Double, aParam() As Variant
 Dim aResult() As Double
 Dim i As Integer

 adParam = vParam
 'if vParam is a single value, then adParam also is a single value
 'if vParam is a range, then adParam is a variant array from this range's values
 'if vParam is a array literal, then adParam is a variant array from this array literal

 If TypeName(adParam) = "Variant()" Then 'we have a variant array
  'it could be one dimensional (row vector) or two dimensional (column vector)
  'we will only process one dimensional array, so we must transform if needed
  i = 0
  For Each vParam In adParam
   ReDim Preserve aParam(i)
   aParam(i) = vParam
   i = i + 1
  Next
 ElseIf TypeName(adParam) = "Double" Or TypeName(adParam) = "String" Then  'we have a single value, either a double or a string
  ReDim aParam(0)
  aParam(0) = adParam
 End If
 'now we have an array (one dimensional) in any case

 For i = LBound(aParam) To UBound(aParam)
  ReDim Preserve aResult(i)
  aResult(i) = Val(Replace(aParam(i), "½", ".5")) 'this is the function's main operation.
 Next

 If UBound(aResult) = 0 Then
  'if only one result
  arrayFriendlyUDF = aResult(0)
 Else
  'return the array of results
  arrayFriendlyUDF = aResult
 End If

End Function

表:

enter image description here

我的语言环境是德语。所以十进制分隔符是逗号。

公式:

<{1}}中的

B1:B9

<{1}}中的

=arrayFriendlyUDF(A1)

<{1}}中的

D2:L2

<{1}}中的

=arrayFriendlyUDF(D2)

在这种情况下,数组上下文不是必需的。但该公式也可用于数组上下文中。

答案 3 :(得分:0)

有点晚了,但有些方法可以在没有循环的情况下返回数组:

Public Function f(v)
    v = Application.Transpose(v)    ' 2D to 1D because Join needs 1D array
    v = Join(v, ";")                ' "1½;2½"
    v = Replace(v, "½", ".5")       ' "1.5;2.5"
    f = Evaluate("{" & v & "}")     ' {1.5;2.5}
End Function

如果它还需要适用于行或单个单元格,那就有点复杂了:

Public Function f(v)
    Let v = v               ' Range to 2D Array or value
    If IsArray(v) Then
        If UBound(v, 1) = 1 Then
            v = Application.Index(v, 1, 0)  ' 2D row array to 1D
            v = "{" & Join(v, ",") & "}"    ' Join needs 1D array
        Else
            v = Application.Transpose(v)    ' 2D column array to 1D
            v = "{" & Join(v, ";") & "}"    ' ; is row separator
        End If
    End If
    v = Replace(v, "½", ".5")   ' "{1.5;2.5}"
    f = Evaluate(v)             '  {1.5;2.5}
End Function

但最好和最快的选择很可能是For循环:

Public Function f(v)
    Let v = v               ' Range to 2D Array or value
    If Not IsArray(v) Then f = Val(Replace(v, "½", ".5")): Exit Function

    Dim r As Long, c As Long
    For r = 1 To UBound(v, 1)
        For c = 1 To UBound(v, 2)
            v(r, c) = Val(Replace(v(r, c), "½", ".5"))
        Next c
    Next r
    f = v
End Function

在Excel 2016中,TEXTJOIN函数可用于将任何范围展平为数组(未测试):

Public Function f(r As Range)
    f = r.Worksheet.Evaluate("TEXTJOIN(("","",1," & r.Address & ")")    ' "1½,2½"
    f = Replace(f, "½", ".5")                                           ' "1.5,2.5"
    f = Evaluate("{" & f & "}")                                         ' {1.5,2.5}
End Function