0

I am working on a project in which I have to generate a table of output from a range of data. I am able to generate Unique values from the list of data and I am able to calculate Count, Mean and Standard Deviation for the individual values. But, I am not able to connect these two functions. Can anyone tell a solution to how I can execute everything from one function?

I want to call the Uniques function in the code from the array output and then execute a mathematical function on these values.

Code

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
6
  • Sounds like you want a sub to determine the order of events and to call the various functions and do something with their return values. You don't really want one super function. Commented Jan 29, 2021 at 9:08
  • 1
    I am afraid, the way you asked is not so friendly... Not all people will loose time trying to understand your (a lot of) code. So, please try explaining in words what you are trying accomplishing. You proved that tried something... What I can understand from your picture is: The three columns to the left is the range to be processed (It should be good to see the columns and rows headers...). And you must obtain the right down situation which means in obtaining the unique values, their count, the average for the count and standard deviation. Is this understanding correct? Commented Jan 29, 2021 at 9:11
  • @FaneDuru Thanks for the feedback, I agree I can explain it better. I was in a bit of panic mode to be honest. So what I am trying to do is pick unique values from the rating and coupon data and trying to calculate their data in the small table. Yes I am trying to obtain the unique rating values ( "A","AAA",etc) and there corresponding count, mean and Standard Deviation Commented Jan 29, 2021 at 9:41
  • @QHarr for this problem I need a function and not a sub, is there a way to call a sub from a function ? Commented Jan 29, 2021 at 9:42
  • You can call a Sub from a function. But it cannot return anything. I mean it will only run... Commented Jan 29, 2021 at 10:39

1 Answer 1

1

Please, try the next code. It uses a dictionary to solve the unique part, the count and sum, then process its data and populate an array. Its content is dropped at once in the range. The code assumes that the range to be processed is in columns A:C and the processing result is placed in a range starting from "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

Please test it, send some feedback.

If you do not know how to add a reference, please run the next code before running the above one. It will automatically add the necessary reference:

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
Sign up to request clarification or add additional context in comments.

2 Comments

@Kannav Bhatia: Didn't you find some time to test the above code? If tested, didn't it do what you need?
Hey I will test it and let you know ! thanks for the help though :)

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.