Shuffling an array of strings in vb.net

后端 未结 1 1269
甜味超标
甜味超标 2020-11-30 15:23

I am developing a webpage in vb.net that will generate a number of multiple choice questions to the user. I need to shuffle the four answers which are already put in an arra

相关标签:
1条回答
  • 2020-11-30 15:52

    There are several issues with your your Shuffle method and use of Random.

    1. Randomize is for use with the old, legacy VB Rnd function. It has no impact on the shiny new NET Random class.
    2. There is rarely a need to provide a custom seed; in fact this can work against you.
    3. Create one Random for the entire app to use rather than each time you shuffle (or click something). And never create them in a loop - this almost guarantees repeated numbers.

    4. The max argument to Random.Next(min, max) is exclusive, so your range is actually 1 element smaller than it should be.

    5. Your Shuffle is pretty close, but has a few flaws:
      • Generally the NET version of the Fisher-Yates Shuffle is an in place shuffle (Sub) making it very efficient (rather than returning a new collection)
      • It is important to loops backwards thru the list or array.1

    The Standard Fisher-Yates Shuffle:

    ' form/class level var
    Private rnd As New Random()
    
    Public Sub Shuffle(items As String())
        Dim j As Int32
        Dim temp As String
    
        For n As Int32 = items.Length - 1 To 0 Step -1
            j = rnd.Next(0, n + 1)
            ' Swap them.
            temp = items(n)
            items(n) = items(j)
            items(j) = temp
        Next n
    End Sub
    

    Output from 4 shuffles of the same starting array:

    Shuffle #1    Wrong3   Correct  Wrong2   Wrong1   
    Shuffle #2    Correct  Wrong2   Wrong1    Wrong3   
    Shuffle #3    Wrong2   Correct  Wrong3    Wrong1   
    Shuffle #4    Correct  Wrong1   Wrong2    Wrong3   
    Shuffle #5    Correct  Wrong1   Wrong3    Wrong2   
    

    Variations

    Rather than a global Random generator, you can pass it (useful as an extension method):

    Public Sub Shuffle(items As String(), RNG As Random)
    

    Generic method for shuffling many types:

    ' Generic shuffle for basic type arrays
    Public Sub Shuffle(Of T)(items As T(), rng As Random)
        Dim temp As T
        Dim j As Int32
    
        For i As Int32 = items.Count - 1 To 0 Step -1
            ' Pick an item for position i.
            j = rng.Next(i + 1)
            ' Swap 
            temp = items(i)
            items(i) = items(j)
            items(j) = temp
        Next i
    End Sub
    

    Examples:

    Shuffle(intArray, myRnd)
    Shuffle(strArray, myRnd)
    Shuffle(colors, myRnd)
    Shuffle(myButtons, myRnd)
    

    Simple Reordering

    Finally, for something simple where you might only reorder them once, a simple and usually-good-enough version using an extension method:

    Dim ShuffledItems = myItems.OrderBy(Function() rnd.Next).ToArray()
    

    This has less code and is easy to dash off, but is much less efficient.

    1 The reason that you want to loop backwards is to limit each array element to one swap. Once "X" is moved to items(j) in the last step, that position is removed from consideration because rnd.Next(0, n + 1) will only pick up to the last element/loop index. Many implementations get this wrong.

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