如何从 VBA 中的两个数组函数获取单个数组输出?

Posted

技术标签:

【中文标题】如何从 VBA 中的两个数组函数获取单个数组输出?【英文标题】:How do I get single array output from two array functions in VBA? 【发布时间】:2021-01-29 08:21:45 【问题描述】:

我正在做一个项目,我必须从一系列数据中生成一个输出表。我能够从数据列表中生成唯一值,并且能够计算各个值的计数、平均值和标准偏差。但是,我无法连接这两个功能。谁能告诉我如何从一个函数执行所有内容的解决方案?

我想从数组输出中调用代码中的 Uniques 函数,然后对这些值执行数学函数。

代码

Option Explicit

Public Function uniques(myrange As Range)
    Dim list As New Collection
    Dim Ulist() As String
    Dim value As Variant
    Dim i As Integer
    'Adding each value of myrang into the collection.
    On Error Resume Next
    For Each value In myrange
        'here value and key are the same. The collection does not allow duplicate keys hence only unique values will remain.
        list.Add CStr(value), CStr(value)
    Next
    On Error GoTo 0

    'Defining the length of the array to the number of unique values. Since the array starts from 0, we subtract 1.
    ReDim Ulist(list.Count - 1, 0)

    'Adding unique value to the array.
    For i = 0 To list.Count - 1
        Ulist(i, 0) = list(i + 1)
    Next

    'Printing the array
    uniques = Ulist
End Function

Public Function findtext(tofind As String, myrange As Range) As Integer
    
    ' Removed RA from dim
    Dim i As Integer
    Dim rcount As Integer
    rcount = 0

    For i = 1 To myrange.Rows.Count
        'tofind = uniques(myrange.Cells.value)
        If myrange(i, 1) = tofind Then
            rcount = rcount + 1
        End If
    Next i

    findtext = rcount

End Function

Public Function findavg(tofind As String, myrange As Range)
    Dim avg As Double, rcount As Integer
    Dim SUM As Double, findtext As Double
    Dim i As Integer
    SUM = 0
    rcount = 0
    For i = 1 To myrange.Rows.Count
        If myrange(i, 1) = tofind Then
            SUM = SUM + myrange(i, 2)
            rcount = rcount + 1
            avg = SUM / rcount
        End If
    Next i
    findavg = avg

End Function

Public Function findstd(tofind As String, myrange As Range)
    Dim std As Double, rcount As Integer
    Dim SUM As Double, avg As Double, totalstd As Double
    Dim i As Integer
    
    SUM = 0
    std = 0
    rcount = 0
    
    For i = 1 To myrange.Rows.Count              'i to active selection
        If myrange(i, 1) = tofind Then           'criteria = "A"....etc
            SUM = SUM + myrange(i, 2)            'sum in loop
            rcount = rcount + 1                  'add & count in loop
            avg = SUM / rcount
        End If
    Next i
    For i = 1 To myrange.Rows.Count
        If myrange(i, 1) = tofind Then
            std = std + (myrange(i, 2) - avg) ^ 2
        End If
    Next i
    
    findstd = Sqr(std / (rcount - 1))
End Function

Function arrayutput(tofind As String, myrange As Range) As Variant

    'we take it as zero because we haven't taken option base1
    Dim Output(0, 2) As Variant

    Output(0, 0) = findtext(tofind, myrange)     'first column
    Output(0, 1) = findavg(tofind, myrange)      'second column
    Output(0, 2) = findstd(tofind, myrange)

    arrayutput = Output

End Function

【问题讨论】:

听起来你想要一个 sub 来确定事件的顺序并调用各种函数并使用它们的返回值做一些事情。你真的不想要一个超级函数。 恐怕你问的方式不太友好......并不是所有人都会花时间试图理解你的(很多)代码。因此,请尝试用文字解释您要完成的工作。您证明尝试了一些东西...从您的图片中我可以理解的是:左侧的三列是要处理的范围(看到列和行标题应该很好...)。并且您必须获得正确的情况,这意味着获得唯一值、它们的计数、计数的平均值和标准偏差。这种理解正确吗? @FaneDuru 感谢您的反馈,我同意我可以更好地解释它。老实说,我有点恐慌。所以我要做的是从评级和优惠券数据中选择唯一值,并尝试在小表中计算它们的数据。是的,我正在尝试获取唯一的评级值(“A”、“AAA”等)以及相应的计数、平均值和标准偏差 @QHarr 这个问题我需要一个函数而不是一个子函数,有没有办法从函数调用一个子函数? 您可以从函数中调用Sub。但它不能返回任何东西。我的意思是它只会运行...... 【参考方案1】:

请尝试下一个代码。它使用字典来解决唯一部分、计数和总和,然后处理其数据并填充数组。它的内容立即被丢弃在范围内。代码假设要处理的范围在A:C列,处理结果放在从“G2”开始的范围内:

Sub testExtractDataAtOnce()
'the code needs a reference to 'Microsoft Scripting Runtime'
 Dim sh As Worksheet, lastRow As Long, arr, arrIt, arrFin
 Dim i As Long, dict As New Scripting.Dictionary
 
 Set sh = ActiveSheet                   'use here your necessary sheet
 lastRow = sh.Range("B" & sh.Rows.count).End(xlUp).row
 arr = sh.Range("B2:C" & lastRow).Value 'put the range to be processed in an array
 
 For i = 1 To UBound(arr)               'process the array and fill the dictionary
    If Not dict.Exists(arr(i, 1)) Then
        dict.Add arr(i, 1), 1 & "|" & arr(i, 2) 'create the unique key and corresponding count | value
    Else
        arrIt = Split(dict(arr(i, 1)), "|") 'extract the count and previous value and use it in the next line
        'add the count and the new value to the existing key data:
        dict(arr(i, 1)) = CLng(arrIt(0)) + 1 & "|" & CDbl(arrIt(1)) + arr(i, 2)
    End If
 Next i

 ReDim arrFin(1 To dict.count, 1 To 4) 'redim the final array to accept all the necessary fields
 Dim avg As Double, std As Double
 For i = 0 To dict.count - 1           'iterate between the dictionary data
    arrIt = Split(dict.Items(i), "|")  'extract the count and the value (sum)
    arrFin(i + 1, 1) = dict.Keys(i): arrFin(i + 1, 2) = arrIt(0) 'write the key and count
    avg = arrIt(1) / arrIt(0)          'calculate the average (neccessary for the next steps, too)
    arrFin(i + 1, 3) = avg             'put the average in the array
    'call the adapted function (able to extract the stdDev from the array):
    arrFin(i + 1, 4) = findstd(CStr(dict.Keys(i)), avg, CDbl(arrIt(0)), arr)
 Next i
 'Drop the processed result in the sheet, at once. You can use any range instead of "G2" and any sheet
 sh.Range("G2").Resize(UBound(arrFin), 4).Value = arrFin
End Sub

Public Function findstd(tofind As String, avg As Double, rcount As Long, arr)
    Dim std As Double, i As Long

    For i = 1 To UBound(arr)
        If arr(i, 1) = tofind Then
            std = std + (arr(i, 2) - avg) ^ 2
        End If
    Next i
    findstd = Sqr(std / (rcount - 1))
End Function

请测试一下,发送一些反馈。

如果您不知道如何添加引用,请在运行上面的代码之前运行下一个代码。它会自动添加必要的引用:

Sub addScrRunTimeRef()
  'Add a reference to 'Microsoft Scripting Runtime':
  'In case of error ('Programmatic access to Visual Basic Project not trusted'):
  'Options->Trust Center->Trust Center Settings->Macro Settings->Developer Macro Settings->
  '         check "Trust access to the VBA project object model"
  Application.VBE.ActiveVBProject.References.AddFromFile "C:\Windows\SysWOW64\scrrun.dll"
End Sub

【讨论】:

@Kannav Bhatia:你没有抽出时间来测试上面的代码吗?如果经过测试,它没有满足您的需求吗? 嘿,我会测试它并告诉你!感谢您的帮助:)

以上是关于如何从 VBA 中的两个数组函数获取单个数组输出?的主要内容,如果未能解决你的问题,请参考以下文章

如何从vba中的数组中获取一维向量

从工作表将二维数组传递给 VBA/UDF 函数

从 vba 中的 sub 调用函数

从Mongo DB嵌套数组中获取不同的值并输出到单个数组

如何使用数组并在 MsgBox VBA 中显示它们

如何从 JSON 数组中的 JSON 对象中的单个值获取数据?