How can I randomly select a number of cells and display the contents in a message box?

前端 未结 4 1247
-上瘾入骨i
-上瘾入骨i 2021-01-22 13:11

I have a list of ID numbers 1101-1137 in cells A1-A37. I would like to click a button to randomly select 20 of these, with no repetitions, and display them in a message box.

相关标签:
4条回答
  • 2021-01-22 13:18

    Just shuffle the indices:

    Sub MAIN()
       Dim ary(1 To 37) As Variant
       Dim i As Long, j As Long
    
       For i = 1 To 37
          ary(i) = i
       Next i
    
       Call Shuffle(ary)
    
       msg = ""
       For i = 1 To 20
          j = ary(i)
          msg = msg & vbCrLf & Cells(j, 1).Value
       Next i
       MsgBox msg
    End Sub
    
    
    
    Public Sub Shuffle(InOut() As Variant)
        Dim i As Long, j As Long
        Dim tempF As Double, Temp As Variant
    
        Hi = UBound(InOut)
        Low = LBound(InOut)
        ReDim Helper(Low To Hi) As Double
        Randomize
    
        For i = Low To Hi
            Helper(i) = Rnd
        Next i
    
    
        j = (Hi - Low + 1) \ 2
        Do While j > 0
            For i = Low To Hi - j
              If Helper(i) > Helper(i + j) Then
                tempF = Helper(i)
                Helper(i) = Helper(i + j)
                Helper(i + j) = tempF
                Temp = InOut(i)
                InOut(i) = InOut(i + j)
                InOut(i + j) = Temp
              End If
            Next i
            For i = Hi - j To Low Step -1
              If Helper(i) > Helper(i + j) Then
                tempF = Helper(i)
                Helper(i) = Helper(i + j)
                Helper(i + j) = tempF
                Temp = InOut(i)
                InOut(i) = InOut(i + j)
                InOut(i + j) = Temp
              End If
            Next i
            j = j \ 2
        Loop
    End Sub
    

    0 讨论(0)
  • 2021-01-22 13:23

    I've added a little to one line in your code... the line is now:

    strString = strString & vbCrLf & Cells(idx(i), 1).Value
    

    the full code is:

    Private Sub CommandButton1_Click()
    
    Const nItemsToPick As Long = 20
    Const nItemsTotal As Long = 37
    
    Dim rngList As Range
    Dim idx() As Long
    Dim varRandomItems() As Variant
    Dim i As Long
    Dim j As Long
    Dim booIndexIsUnique As Boolean
    
    Set rngList = Range("A1").Resize(nItemsTotal, 1)
    
    ReDim idx(1 To nItemsToPick)
    ReDim varRandomItems(1 To nItemsToPick)
    For i = 1 To nItemsToPick
        Do
            booIndexIsUnique = True ' Innocent until proven guilty
            idx(i) = Int(nItemsTotal * Rnd + 1)
            For j = 1 To i - 1
                If idx(i) = idx(j) Then
                    ' It's already there.
                    booIndexIsUnique = False
                    Exit For
                End If
            Next j
            If booIndexIsUnique = True Then
            strString = strString & vbCrLf & Cells(idx(i), 1).Value
                Exit Do
            End If
        Loop
        varRandomItems(i) = rngList.Cells(idx(i), 1)
    
      Next i
        Msg = strString
        MsgBox Msg
    ' varRandomItems now contains nItemsToPick unique random
    ' items from range rngList.
    
    End Sub
    

    So rather than returning the number, it uses the number returned to look at the value on the row that it relates to.

    0 讨论(0)
  • 2021-01-22 13:29

    If you construct a string containing the IDs already found through randomization, you can check for repeats.

    Dim i As Long, msg As String, id As String
    
    msg = Chr(9)
    For i = 1 To 20
        id = 1100 + Int((37 - 1 + 1) * Rnd + 1)
        Do Until Not CBool(InStr(1, msg, Chr(9) & id & Chr(9)))
            Debug.Print id & msg
            id = 1100 + Int((37 - 1 + 1) * Rnd + 1)
        Loop
        msg = msg & id & Chr(9)
    Next i
    msg = Mid(Left(msg, Len(msg) - 1), 2)
    
    MsgBox msg
    
    0 讨论(0)
  • 2021-01-22 13:38

    another one approach:

    Sub test()
        Dim Dic As Object, i%
        Set Dic = CreateObject("Scripting.Dictionary")
        Dic.comparemode = vbTextCompare
        While Dic.Count <> 20
            i = WorksheetFunction.RandBetween(1, 37)
            If Not Dic.exists(i) Then Dic.Add i, Cells(i, "A")
        Wend
        MsgBox Join(Dic.Items, Chr(13))
    End Sub
    

    test:


    0 讨论(0)
提交回复
热议问题