VBA code to randomly pick from a list of names

danbates77

New Member
Joined
Jan 10, 2017
Messages
36
Office Version
  1. 2016
Hi,

I have this code that randomly picks a different name from a list.
Code:
Sub CommandButton1_Click()

Dim lrcd As Long


SendKeys "%^{F9}"


Range("H31").Copy
'Range("C2:C7").PasteSpecial xlPasteValues


lrcd = Sheets("Sheet1").Range("E" & Rows.Count).End(xlUp).Row


Sheets("Sheet1").Cells(lrcd + 1, "E").PasteSpecial xlPasteValues


End Sub

The F9 part in the code is to trigger this formula which is in H31
Code:
=INDEX(A1:A12,RANDBETWEEN(1,COUNTA(A1:A12)),1)

What I would like is when it randomly picks a name and enters it in column E, it cannot enter that name again.

I hope this makes sense.

Thanks

Dan
 

Excel Facts

How to fill five years of quarters?
Type 1Q-2023 in a cell. Grab the fill handle and drag down or right. After 4Q-2023, Excel will jump to 1Q-2024. Dash can be any character.
Be sure to go to another sheet and then back to the sheet in question, in order to trigger the activate event:

Code:
Dim col As Collection, rb, i%
' sheet module
Sub CommandButton1_Click()
If col.count > 0 Then                                                   ' collection not empty
    rb = WorksheetFunction.RandBetween(1, col.count)
    Me.Cells(Me.Range("E" & Rows.count).End(xlUp).Row + 1, 5) = col(rb) ' write to sheet
    col.Remove CStr(col(rb))                                            ' already used
End If
End Sub


Private Sub Worksheet_Activate()
Set col = New Collection
For i = 1 To Range("a" & Rows.count).End(xlUp).Row
    col.Add CStr(Me.Cells(i, 1)), CStr(Me.Cells(i, 1))      ' possible options
Next
If WorksheetFunction.CountA(Me.[e:e]) > 0 Then
    For i = 1 To Me.Range("e" & Rows.count).End(xlUp).Row
        col.Remove CStr(Me.Cells(i, 5))                     ' already used
    Next
End If
End Sub
 
Upvote 0
Hi,

Thank you for your reply. Unfortunately it is coming up with the following error:

Run time error 91 - Object variable or with blocked variable not set

Code:
If col.Count > 0 Then                                                   ' collection not empty

This is how I have it in my sheet module:

Code:
Option Explicit

Dim col As Collection, rb, i%
' sheet module
Sub CommandButton1_Click()
If col.Count > 0 Then                                                   ' collection not empty
    rb = WorksheetFunction.RandBetween(1, col.Count)
    Me.Cells(Me.Range("E" & Rows.Count).End(xlUp).Row + 1, 5) = col(rb) ' write to sheet
    col.Remove CStr(col(rb))                                            ' already used
End If
End Sub




Private Sub Worksheet_Activate()
Set col = New Collection
For i = 1 To Range("a" & Rows.Count).End(xlUp).Row
    col.Add CStr(Me.Cells(i, 1)), CStr(Me.Cells(i, 1))      ' possible options
Next
If WorksheetFunction.CountA(Me.[e:e]) > 0 Then
    For i = 1 To Me.Range("e" & Rows.Count).End(xlUp).Row
        col.Remove CStr(Me.Cells(i, 5))                     ' already used
    Next
End If
End Sub

Thanks again

Dan
 
Upvote 0
I did not receive an email warning me about your post. If I do not answer again, send me a PM.
New version is below,note that there is a new reset button.


Code:
Dim col As Collection, rb, i%
' sheet module
Sub CommandButton1_Click()
If col Is Nothing Then DoThing
If col.Count > 0 Then                                                   ' collection not empty
    rb = WorksheetFunction.RandBetween(1, col.Count)
    Me.Cells(Me.Range("E" & Rows.Count).End(xlUp).Row + 1, 5) = col(rb) ' write to sheet
    col.Remove CStr(col(rb))                                            ' already used
End If
End Sub

Sub DoThing()
Set col = New Collection
For i = 1 To Range("a" & Rows.Count).End(xlUp).Row
    col.Add CStr(Me.Cells(i, 1)), CStr(Me.Cells(i, 1))      ' possible options
Next
If WorksheetFunction.CountA(Me.[e:e]) > 0 Then
    For i = 1 To Me.Range("e" & Rows.Count).End(xlUp).Row
        col.Remove CStr(Me.Cells(i, 5))                     ' already used
    Next
End If
End Sub

Private Sub CommandButton2_Click()                          ' reset button
Me.[e:e].ClearContents
DoThing
End Sub

Private Sub Worksheet_Activate()
DoThing
End Sub
 
Last edited:
Upvote 0
Hi Worf,

I have forgot to mention I have a header in cell E6. This code works perfectly when I delete the header but I would prefer to keep the header if that's ok?

Thanks again for all your help.

Kind Regards

Dan
 
Upvote 0
Hi Dan

I am going off-line now but will work on it as soon as possible…
 
Last edited:
Upvote 0
New version:

Code:
Dim col As Collection, rb, i%, lr%
' sheet module
Sub CommandButton1_Click()
If col Is Nothing Then DoThing
If col.Count > 0 Then                                                   ' collection not empty
    rb = WorksheetFunction.RandBetween(1, col.Count)
    Me.Cells(Me.Range("E" & Rows.Count).End(xlUp).Row + 1, 5) = col(rb) ' write to sheet
    col.Remove CStr(col(rb))                                            ' already used
End If
End Sub

Sub DoThing()
Set col = New Collection
For i = 1 To Range("a" & Rows.Count).End(xlUp).Row
    col.Add CStr(Me.Cells(i, 1)), CStr(Me.Cells(i, 1))      ' possible options
Next
lr = Me.Range("e" & Rows.Count).End(xlUp).Row
If WorksheetFunction.CountA(Me.Range("e7:e" & lr)) > 0 Then
    For i = 7 To lr
        col.Remove CStr(Me.Cells(i, 5))                     ' already used
    Next
End If
End Sub
Private Sub CommandButton2_Click()                          ' reset button
Me.[e7:e1000].ClearContents
DoThing
End Sub
Private Sub Worksheet_Activate()
DoThing
End Sub
 
Upvote 0
Here is another option to test.
Code:
Private Sub CommandButton1_Click()
  Dim d As Object
  Dim i As Long
  Dim Resp As VbMsgBoxResult
  
  Set d = CreateObject("Scripting.Dictionary")
  For i = 1 To Range("A" & Rows.Count).End(xlUp).Row
    d(Range("A" & i).Value) = Empty
  Next i
  For i = 7 To Range("E" & Rows.Count).End(xlUp).Row
    d.Remove Range("E" & i).Value
  Next i
  If d.Count > 0 Then
    Randomize
    Range("E" & Rows.Count).End(xlUp).Offset(1).Value = d.Keys()(Int(Rnd() * d.Count))
  Else
    Resp = MsgBox("List exhausted. Clear items from column E?", vbYesNo)
    If Resp = vbYes Then Range("E7", Range("E" & Rows.Count).End(xlUp)).ClearContents
  End If
End Sub
 
Last edited:
Upvote 0
I'm not expert enough on what is happening behind the scenes with that but I have just run quite a few tests creating up to 20,000 sets of results with my code and with the structure suggested in that link and to be honest I cannot see any discernible difference in the "randomness" of the results. However, I see no disadvantage in checking if Randomize has already been applied so no problem if the OP wants to incorporate that. :)
 
Upvote 0

Forum statistics

Threads
1,214,936
Messages
6,122,340
Members
449,079
Latest member
rocketslinger

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top