2

I want apply a user defined aggregation function (string-value from a certain cell, like "SUM" or "STDEV") on an array of values. Here's a simplified example. However I don't know how to make the aggregation (last line):

Sub test()
    Dim values() As Double
    ReDim values(1 To 3)
    values(1) = 3.5
    values(2) = 5
    values(3) = 4.8

    Dim aggregate_fn As String
    aggregate_fn = "SUM"       

    Dim result As Double
    result = Evaluate("=" & aggregate_fn & "(" & values & ")")  ' <-- This doesn't work, but hopefully it's clear what it should do

End Sub

EDIT

My original code is also creating the values array dynamically from a spreadsheet which uses , as decimal sign. This causes an issue with Scott's answer below.

Const datasht = "Daten"
Const aggregate_cell = "G1"

Sub run()
    Dim sht As Worksheet
    Dim n_rows As Integer
    Dim rw As Integer

    Application.DecimalSeparator = "."

    Set sht = ActiveWorkbook.Worksheets(datasht)
    n_rows = sht.Cells(1, 1).CurrentRegion.Rows.Count  ' Get range of data

    Dim values() As String
    ReDim values(1 To n_rows)

    For rw = 1 To n_rows
        values(rw) = sht.Cells(rw, 1).Value
    Next rw
    Debug.Print (aggregate(values))

End Sub

Function aggregate(values() As String)
    ' Get aggregated value
    Dim aggregate_fn As String
    aggregate_fn = ActiveWorkbook.Worksheets(datasht).Range(aggregate_cell).Value
    aggregate = Evaluate("=" & aggregate_fn & "(" & Join(values, ",") & ")") ' <-- doesn't work as intended

End Function
1
  • 1
    Use Join(values,",") instead of values Commented Apr 23, 2018 at 15:33

3 Answers 3

2

This should work for any function available via Application.WorksheetFunction, and is less likely to give an error if you pass too many values.

Sub Tester()

    Dim arr(0 To 1000), res, x As Long, f as String

    'get some values to work with...
    For x = 0 To 1000
        arr(x) = Rnd() * 10
    Next x

    f = "SUM"

    res = CallByName(Application.WorksheetFunction, f, VbMethod, arr)

    Debug.Print res

End Sub
Sign up to request clarification or add additional context in comments.

1 Comment

This also works correctly if the application's decimal sign is ,
1

I was able to get this to work by creating a string from your array, then using that instead:

Sub test()

    Dim values() As Double
    ReDim values(1 To 3)
    values(1) = 3.5
    values(2) = 5
    values(3) = 4.8

    Dim mystring As String, i As Long
    mystring = values(LBound(values))

    For i = LBound(values) + 1 To UBound(values)
        mystring = mystring & "," & values(i)
    Next i

    Dim aggregate_fn As String
    aggregate_fn = "SUM"

    Dim result As Double
    result = Evaluate("=" & aggregate_fn & "(" & mystring & ")")

    Debug.Print result

End Sub

img1

1 Comment

@LatafaShi Added picture above - cannot reproduce your results.
1

Join works with Strings change the values to String instead of Double:

Sub test()
    Dim values() As String
    ReDim values(1 To 3)
    values(1) = 3.5
    values(2) = 5
    values(3) = 4.8

    Dim aggregate_fn As String
    aggregate_fn = "SUM"

    Dim result As Double
    result = Evaluate("=" & aggregate_fn & "(" & Join(values, ",") & ")")
    Debug.Print result
End Sub

enter image description here


As per your edit there is no need for the array at all, just pass the range and worksheet to the function and use .Address on the range.

Const datasht = "Daten"
Const aggregate_cell = "G1"

Sub run()
    Dim sht As Worksheet
    Dim n_rows As Integer
    Dim rw As Integer

    'Application.DecimalSeparator = "."

    Set sht = ActiveWorkbook.Worksheets(datasht)
    n_rows = sht.Cells(1, 1).CurrentRegion.Rows.Count  ' Get range of data

    Dim rng As Range
    Set rng = sht.Range(sht.Cells(1, 1), sht.Cells(n_rows, 1))

    Debug.Print (aggregate(sht, rng))

End Sub

Function aggregate(sht As Worksheet, rng As Range)
    ' Get aggregated value
    Dim aggregate_fn As String
    aggregate_fn = sht.Range(aggregate_cell).Value
    aggregate = sht.Evaluate("=" & aggregate_fn & "(" & rng.Address(1, 1) & ")") 
End Function

12 Comments

@LatifaShi not sure why yours is different unless you are using , instead of . that vba requires.
Same for me. Join(values, ",") result in 3,5,5,4,8 if you have , as decimal sign. Do you know how to change decimal sign during runtime of the procedure?
@ascripter you need to show then how you are loading the array in the first place. Because as per your question you are putting the values in directly in EN-US format.
@ascripter Just loop through array LBound(values) to UBound(values), values(i) = Replace(values(i), ",", ".").
@dwirony but if the OP is loading a consecutive range then skip the whole array and just use: result = Worksheet("Sheet1").Evaluate(aggregate_fn & "(" & Range("A1:A3").Address(1,1) & ")") that is why I want to see how the array is being loaded, it may be unnecessary.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.