2017-04-18 48 views
0

工作以我wooksheet我有细胞:A1 = 1,A2 = 2件EXCEL SUM不与UDF在ARRAY

此公式作品当然在片材的一个细胞:

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

但我有像值:A1:1.5和A2 = 2.5 但这阵列(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 

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

编辑。我已经改变了我的功能和两个单元格值更加精确!

+1

你传入一个'Range'到你的UDF它接受的变体。然后你的UDF试图将'Variant/Range'乘以2并失败(因为你不能对范围进行算术运算)。 – YowE3K

+0

如何克服? – danKV

+0

我认为你需要单独处理'value'中的每个单元格,将结果放入一个Variant数组(它具有与源范围相同的形状),然后将该Variant数组作为UDF的结果返回。但是,除非您可以限制用户输入以及结果会发生什么 - 例如,这会变得困难。你需要允许输入'myUserDefinedFkt((A1:A2,B7))',你是否需要允许使用UDF的结果而不用'SUM'等。 – YowE3K

回答

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

我的语言环境是德国人。所以小数分隔符是逗号。

公式:

B1:B9=arrayFriendlyUDF(A1)

D2:L2=arrayFriendlyUDF(D2)

A11=SUM(arrayFriendlyUDF(A1:A9))

N1=SUM(arrayFriendlyUDF(D1:L1))

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

0

使用以下用户定义函数= UDFSumstring(A1:B10)
无需阵列式只是输入
该UDF

  • 替代所有 “1/2” 到” 0.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 
+0

结果比事实上更复杂。它不仅仅是双倍的例子,而且它必须进入每个单元才能得到另一个值(单元中的f.ex:2½会得到2.5的值等),所以我不能使用你的建议,因为2½+2½会得到一个错误 – danKV

+0

你的意思是UDF转换的分数和总和会增加结果? – yass

+0

是的,这正是我想要的。 – danKV

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

+0

谢谢你的回答。什么,我想要的是最优雅的解决方案。想象一下,我有1234个条目的行/列,公式将会很长!这里最好的解决方案是在@YowE3K建议的myUserDefinedFkt中遍历整个单元格区域。 – danKV

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 
+0

不错,你分享清晰的想法。 – danKV