【问题标题】:vba pass a group of cells as range to functionvba 将一组单元格作为范围传递给函数
【发布时间】:2013-08-11 02:25:55
【问题描述】:

我正在获取一组单元格并在下面的函数中对它们进行一些计算。

如果我传递一个范围(带有: 符号)作为第一个参数,它会起作用,但如果我选择一些单元格作为它的范围(A1, A3, B6, B9),它会失败。它只是在逗号之前获取第一个单元格作为第一个参数。但我想要整个细胞。

我能做什么? (除了使用字符串传递范围)

Function calculateIt(Sessions As Range, Customers As Range) As Single
    ' calculate them...
End Function

还有一点:是否可以将一组范围作为参数传递?怎么样?

【问题讨论】:

  • 作为 ParamArray 的替代方案,可以将定义的名称分配给您的一组不相交的单元格并传递名称。

标签: vba excel


【解决方案1】:

正如所写,您的函数只接受两个范围作为参数。

要允许在函数中使用可变数量的范围,您需要在参数列表中声明一个 ParamArray 变体数组。然后,您可以依次处理数组中的每个范围。

例如,

Function myAdd(Arg1 As Range, ParamArray Args2() As Variant) As Double
    Dim elem As Variant
    Dim i As Long
    For Each elem In Arg1
        myAdd = myAdd + elem.Value
    Next elem
    For i = LBound(Args2) To UBound(Args2)
        For Each elem In Args2(i)
            myAdd = myAdd + elem.Value
        Next elem
    Next i
End Function

然后可以在工作表中使用此函数来添加多个范围。

对于您的函数,存在可以传递给函数的范围(或单元格)中的哪些是“会话”以及哪些是“客户”的问题。

最容易处理的情况是,如果您决定第一个范围是 Sessions,而任何后续范围都是客户。

Function calculateIt(Sessions As Range, ParamArray Customers() As Variant) As Double
    'This function accepts a single Sessions range and one or more Customers
    'ranges
    Dim i As Long
    Dim sessElem As Variant
    Dim custElem As Variant
    For Each sessElem In Sessions
        'do something with sessElem.Value, the value of each
        'cell in the single range Sessions
        Debug.Print "sessElem: " & sessElem.Value
    Next sessElem
    'loop through each of the one or more ranges in Customers()
    For i = LBound(Customers) To UBound(Customers)
        'loop through the cells in the range Customers(i)
        For Each custElem In Customers(i)
            'do something with custElem.Value, the value of
            'each cell in the range Customers(i)
            Debug.Print "custElem: " & custElem.Value
         Next custElem
    Next i
End Function

如果您想包含任意数量的 Sessions 范围和任意数量的 Customers 范围,那么您将必须包含一个参数来告诉函数,以便它可以将 Sessions 范围与 Customers 范围分开。

此参数可以设置为函数的第一个数字参数,该参数将识别以下参数中有多少是会话范围,其余参数隐式为客户范围。该函数的签名将是:

Function calculateIt(numOfSessionRanges, ParamAray Args() As Variant)

或者它可以是一个“守卫”参数,将会话范围与客户范围分开。然后,您的代码必须测试每个参数以查看它是否是守卫。该函数如下所示:

Function calculateIt(ParamArray Args() As Variant)

也许有这样的电话:

calculateIt(sessRange1,sessRange2,...,"|",custRange1,custRange2,...)

然后程序逻辑可能是这样的:

Function calculateIt(ParamArray Args() As Variant) As Double
   ...
   'loop through Args
   IsSessionArg = True
   For i = lbound(Args) to UBound(Args)
       'only need to check for the type of the argument
       If TypeName(Args(i)) = "String" Then
          IsSessionArg = False
       ElseIf IsSessionArg Then
          'process Args(i) as Session range
       Else
          'process Args(i) as Customer range
       End if
   Next i
   calculateIt = <somevalue>
End Function

【讨论】:

  • 谢谢,但对我来说有点不清楚。你能给我一个例子吗?如果我想将您的myAdd 函数与我的calculateIt 函数匹配,Arg1 将是SessionsArg2 将是Customers
  • 哇!精彩的!使用保护参数就是答案。再次感谢!
  • @chuff,我没有得到任何结果。我什至在代码中添加了Stop,但在立即窗口 中看不到任何参数。函数也返回 0。知道这里有什么问题吗?
  • 嗨,我有一个与 myAdd 类似的功能,目前接受一个范围和多个值。现在我的要求已更改为接受多个范围,每个范围都分配一个值,例如 SUMIFS 公式。如何在 VBA 中实现这一点?
【解决方案2】:

还有另一种方法可以将多个范围传递给一个函数,我认为这对用户来说感觉更清晰。在电子表格中调用函数时,将每组范围括在括号中,例如:calculateIt( (A1,A3), (B6,B9) )

上述调用假设您的两个会话位于 A1 和 A3 中,而您的两个客户位于 B6 和 B9 中。

要完成这项工作,您的函数需要遍历输入范围中的每个 Areas。例如:

Function calculateIt(Sessions As Range, Customers As Range) As Single

    ' check we passed the same number of areas
    If (Sessions.Areas.Count <> Customers.Areas.Count) Then
        calculateIt = CVErr(xlErrNA)
        Exit Function
    End If

    Dim mySession, myCustomers As Range

    ' run through each area and calculate
    For a = 1 To Sessions.Areas.Count

        Set mySession = Sessions.Areas(a)
        Set myCustomers = Customers.Areas(a)

        ' calculate them...
    Next a

End Function

好消息是,如果您将两个输入都设置为连续范围,则可以像调用普通函数一样调用此函数,例如calculateIt(A1:A3, B6:B9).

希望有帮助:)

【讨论】:

  • 虽然ParamArray 是一个不错的方法,但此选项为多单元格参数提供了一种非常简洁的方法。它应该得到更多的选票......
  • 这个函数不能作为calculateIt(A1:A3, B6:B9)工作。受你的启发,我写了一个更好的版本,它也适用于连续的单元格选择。
【解决方案3】:

由于我是 vba 的初学者,我愿意深入了解 vba 的所有 excel 内置函数是如何工作的。

所以关于上面的问题我已经付出了基本的努力。

Function multi_add(a As Range, ParamArray b() As Variant) As Double

    Dim ele As Variant

    Dim i As Long

    For Each ele In a
        multi_add = a + ele.Value **- a**
    Next ele

    For i = LBound(b) To UBound(b)
        For Each ele In b(i)
            multi_add = multi_add + ele.Value
        Next ele
    Next i

End Function

-a:上面的代码减去这个值会导致计数加倍,所以你添加的值会将第一个值加两次。

【讨论】:

    【解决方案4】:

    受@Ian S 启发,我写了一个更好的函数。

    ' Similar to SUMPRODUCT, but it works with non consecutive cells also, multiplying the price, in the first column, with
    ' the correspondent rate exchange of the second column.
    ' Usage:
    ' SUMCURRENCIES(D6:D10,E6:E10) will multiply D6 by E6, D7 by E7, and so on, finally sum all the multiplications.
    ' SUMCURRENCIES((D113,D117),(E113,E117)) instead will multiply D113 by E113 first, and then will add the result of D117 * E117.
    Function SUMCURRENCIES(Prices As Range, ExchangeRates As Range) As Double
    
        ' Check if we passed the same number of areas.
        If (Prices.Areas.Count <> ExchangeRates.Areas.Count) Then
            SUMCURRENCIES = CVErr(xlErrNA)
            Exit Function
        End If
    
        Dim Price, ExchangeRate As Range
        Dim AreasCount, PricesCount As Integer
        
        Total = 0
        
        ' Runs through each area and multiple the value for the exchange rate.
        AreasCount = Prices.Areas.Count
        For i = 1 To AreasCount
            Set Price = Prices.Areas(i)
            Set ExchangeRate = ExchangeRates.Areas(i)
        
            If VarType(Price.Value2) = VBA.VbVarType.vbDouble Then
                Total = Price * ExchangeRate + Total
            Else
                PricesCount = Prices.Count
                For j = 1 To PricesCount
                    Total = Prices(j).Value * ExchangeRates(j).Value + Total
                Next j
            End If
        Next i
        
        SUMCURRENCIES = Total
    End Function
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多