【问题标题】:VBA Public Function "Compile Error: Expected: List separator or )"VBA 公共函数“编译错误:预期:列表分隔符或)”
【发布时间】:2025-12-17 01:45:01
【问题描述】:

我正在编写我的第一个函数,并且正在为加权平均公式创建一个函数。

当我将它用作子程序并定义值时,这可以正常工作,但是在即时窗口中测试函数时出现此错误。

我尝试过使用数据类型无济于事。

任何帮助将不胜感激。

enter image description here

Public Function WeightedAverage(data() As Range, values() As Range, TotalValue As Range) As Double

Dim i As Integer

Dim Sum As Variant

    For i = 1 To UBound(data)
    
    Sum = Sum + values(i, 1) / TotalValue * data(i, 1)
    
    Next i
    
    WA = Sum / UBound(data)
    
End Function

enter image description here

【问题讨论】:

  • 只要把它扔到一个单元格中,然后这样使用,就容易多了。如果您通过代码执行此操作,则需要使用 VBA 表示法来指定范围。更不用说您的最后一个参数被指定为一个范围并且您正在传递“150”。你需要检查一下。参数总体上不太对,这里有一点改动。

标签: excel vba function compiler-errors compilation


【解决方案1】:

加权平均 UDF

  • 无论你在这里做什么,根据这个link,这不是你计算加权平均值的方式(最后一个参数似乎多余,在循环中划分是错误的)。
  • 如果存在不包含数值的单元格,则提供的链接中建议的 SUMPRODUCT/SUM 公式解决方案将失败,而以下函数将忽略(跳过)这些单元格。

加权平均

Option Explicit

Function WeightedAverage( _
    ByVal ScoreColumnRange As Range, _
    ByVal WeightColumnRange As Range) _
As Double
    
    ' Compare the number of rows and use the smaller number.
    Dim rCount As Long: rCount = ScoreColumnRange.Rows.Count
    Dim wrCount As Long: wrCount = WeightColumnRange.Rows.Count
    If wrCount < rCount Then rCount = wrCount
    
    ' Create the references to the column ranges.
    Dim srg As Range: Set srg = ScoreColumnRange.Cells(1).Resize(rCount)
    Dim wrg As Range: Set wrg = WeightColumnRange.Cells(1).Resize(rCount)
    
    ' Write the values from the column ranges to arrays.
    Dim sData As Variant, wData As Variant
    If rCount = 1 Then
        ReDim sData(1 To 1, 1 To 1): sData(1, 1) = srg.Value
        ReDim wData(1 To 1, 1 To 1): wData(1, 1) = wrg.Value
    Else
        sData = srg.Value
        wData = wrg.Value
    End If
    
    ' Declare additional variables to be used in the For...Next loop.
    Dim sVal As Variant, wVal As Variant ' Current Values
    Dim r As Long ' Rows Counter
    Dim tWeight As Double ' Total Weight
    Dim tProduct As Double ' Total Sum
    
    ' Calculate the total weights and the total products.
    For r = 1 To UBound(sData, 1)
        sVal = sData(r, 1)
        If IsNumeric(sVal) Then ' prevent invalid score
            wVal = wData(r, 1)
            If IsNumeric(wVal) Then ' prevent invalid weight
                tWeight = tWeight + wVal
                tProduct = tProduct + sVal * wVal
            End If
        End If
    Next r
    If tWeight = 0 Then Exit Function ' all were invalid
    
    ' Calculate and return the weighted average (the result).
    WeightedAverage = tProduct / tWeight ' maybe you want to round?

End Function

您的代码已修改

Function WeightedAverage( _
    ByVal DataColumnRange As Range, _
    ByVal ValuesColumnRange As Range, _
    ByVal TotalValue As Double) _
As Double
    
    ' Compare the number of rows and use the smaller number.
    Dim rCount As Long: rCount = DataColumnRange.Rows.Count
    Dim vrCount As Long: vrCount = ValuesColumnRange.Rows.Count
    If vrCount < rCount Then rCount = vrCount
    
    ' Create the references to the column ranges.
    Dim drg As Range: Set drg = DataColumnRange.Cells(1).Resize(rCount)
    Dim vrg As Range: Set vrg = ValuesColumnRange.Cells(1).Resize(rCount)
    
    ' Write the values of the column ranges to arrays.
    Dim dData As Variant, vData As Variant
    If rCount = 1 Then
        ReDim dData(1 To 1, 1 To 1): dData(1, 1) = drg.Value
        ReDim vData(1 To 1, 1 To 1): vData(1, 1) = vrg.Value
    Else
        dData = drg.Value
        vData = vrg.Value
    End If
    
    ' Declare additional variables to be used in the For...Next loop.
    Dim dVal As Variant, vVal As Variant ' Current Values
    Dim r As Long ' Rows Counter
    Dim tCount As Long ' Total Count
    Dim Total As Double ' Total Value
    
    ' Calculate the Total? (there should be a math term for it)
    For r = 1 To UBound(dData, 1)
        dVal = dData(r, 1)
        If IsNumeric(dVal) Then ' prevent invalid data
            vVal = vData(r, 1)
            If IsNumeric(vVal) Then ' prevent invalid value
                tCount = tCount + 1
                Total = Total + dVal * vVal / TotalValue
            End If
        End If
    Next r
    
    If tCount = 0 Then Exit Function ' all were invalid
    
    ' Calculate and return the weighted average (the result).
    WeightedAverage = Total / tCount ' maybe you want to round?

End Function

【讨论】:

  • 感谢您的帮助。那太棒了。对不起,我是 VBA 代码的新手,所以没有添加太多。我计算加权平均值的问题是我的原始数据中没有权重列,并且必须手动创建,因此我想要一个函数来处理计算权重并将其应用于我需要的任何值.
  • - 只是想补充一点,你在那里写的东西非常适合我想要的东西 - 干杯伙伴
  • 对不起最后的评论...这真的很有帮助,因为我什至没有考虑考虑非数字值并正确定义数组 - 特别是当我拿起带有标题等的整个列时。我最后去掉了“/ tcount”,虽然不需要它。与手动计数相一致,它很有魅力 - 干杯
  • 抱歉没有理解加权平均的概念。现在更清楚了(您使用的是没有最后一个除法的第二个函数)。当有人对写作特别感兴趣时,会令人耳目一新。感谢您的回复。
【解决方案2】:

正如@Skin 提到的,您可以稍微修改一下您的代码。我删除了参数部分中的括号。此外,您应该在一个单元格中调用该函数并将每个参数分配给一个单元格/一系列单元格。

变量“WA”未在代码中的任何位置定义。这可能会导致您的错误。要从用户定义函数 (UDF) 获取返回值,您应该将变量“sum”分配给函数名称。

如果我的反馈是对您问题的有效答案,请将其标记为答案。谢谢!

Public Function WeightedAverage( _
    data As Range, _
    values As Range, _
    TotalValue As Range _
        ) As Double

    Dim i As Integer
    
'You need containers for your parameters, which can be more then one cell

    Dim arrData As Variant: arrData = data
    Dim arrValues As Variant: arrValues = values
    
    Dim Sum As Double
    
'Both arrays need the same size, optional, I thought that might help a little bit
    
    If UBound(arrData, 1) <> UBound(arrValues) Then Exit Function

    For i = 1 To UBound(arrData, 1)

    Sum = Sum + arrValues(i, 1) / TotalValue * arrData(i, 1)

    Next i

'Assign the variable "sum" to the functions name

    WeightedAverage = Sum / UBound(arrData, 1)

End Function

【讨论】:

  • 感谢谢尔盖!是的,问题是我没有创建这些容器。我是 VBA 新手(您可能会说...)。