Search code examples
excelvbafunction

VBA How to create an array formula


I'm trying to create a custom function to fill selected cells with unique random numbers. My problem is to get the range of selected cells eg.

=randm()

My problem is that I don't know the cells range to fill

I need to get the range address H16:J24

Is it possible ?

Regards.


Solution

  • You are facing several issues when you want to use a UDF (User defined formula) to fill the selected range:

    • You can't pass the selection (the current selected cells) as parameter
    • A UDF can't write to the sheet. It can only calculate something and Excel writes the result into the cell where the formula is used.
    • You cannot create a spill function with VBA (Update: I was wrong, you can.)
    • If it would be possible to create such a function, it would be triggered whenever Excel thinks that it needs to recalculate the sheet. As the function creates random numbers, the range would be filled newly with every sheet recalculation - probably not what you want.

    So instead, write a Subroutine that fills the Range:

    Sub randM(Optional r As Range = Nothing)
        If r Is Nothing Then Set r = Selection
        
        Dim valueList As Collection, i As Long
        Set valueList = GetRandomValueList
        
        Dim cell As Range
        For Each cell In r
            Dim randomIndex As Long, randVal As Double
            randomIndex = Int((Rnd * valueList.Count) + 1)
            cell.Value = valueList(randomIndex)
            valueList.Remove randomIndex
    
            If valueList.Count = 0 Then Exit Sub  ' No more possible values.
        Next
    End Sub
    

    Now you need a simple routine that fills a list (I use a Collection) with possible values. The following example creates a deck of cards:

    Private Function GetRandomValueList() As Collection
        Dim valueList As New Collection
        Dim i, j
        For Each i In Array(2, 3, 4, 5, 6, 7, 8, 9, 10, "Jack", "Queen", "King", "Ace")
            For Each j In Array("Spade", "Hearts", "Diamonds", "Clubs")
                valueList.Add i & " of " & j
            Next
        Next
        Set GetRandomValueList = valueList
    End Function
    

    And as you can only call parameterless Subroutines from Excel, just create a wrapper that runs on the current Selection

    Sub randMOnSelection
        randM Selection
    End Sub
    

    Now just call this routine whenever you need a range filled with random numbers. You can do this from the Macro-Menu (Developer->Macros or View->Macros). You can also assign the Macro to a Key (eg Ctrl+Shift+R) in the Macro Menu under [Options...]. Or you place a button or shape on your sheet that calls this routine.

    enter image description here