【问题标题】:Shuffling an array of strings in vb.net在 vb.net 中对字符串数组进行洗牌
【发布时间】:2015-03-31 01:01:18
【问题描述】:

我正在 vb.net 中开发一个网页,该网页将为用户生成许多多项选择题。我需要对已经放入数组中的四个答案进行洗牌。让我们假设我必须关注数组:

array = {"Correct", "Wrong1", "Wrong2", "Wrong3"}

我尝试使用以下方法:

Public Shared Function Shuffle(ByVal items() As String) As Array
        Dim max_index As Integer = items.Length - 1
        Dim rnd As New Random(DateTime.Now.Millisecond)
        For i As Integer = 0 To max_index
            ' Pick an item for position i.
            Randomize()
            Dim j As Integer = rnd.Next(i, max_index)
            ' Swap them.
            Dim temp As String = items(i)
            items(i) = items(j)
            items(j) = temp
        Next i
        Return items
    End Function

该功能工作得很好,但我的问题是,如果我有四个问题,每个问题的答案将被打乱,但正确答案将在一个位置,例如:

    array = {"Wrong1", "Correct", "Wrong2", "Wrong3"}
    array = {"Wrong2", "Correct", "Wrong3", "Wrong1"}
    array = {"Wrong3", "Correct", "Wrong1", "Wrong2"}
    array = {"Wrong1", "Correct", "Wrong3", "Wrong2"}

我需要的是将其位置从一个问题更改为另一个问题的正确答案。 感谢您的帮助。

【问题讨论】:

    标签: .net arrays vb.net


    【解决方案1】:

    您的 Shuffle 方法和 Random 的使用存在几个问题。

    1. Randomize 用于旧的遗留 VB Rnd 函数。它对闪亮的新 NET Random 类没有影响。
    2. 很少需要提供自定义种子;事实上,这可能对你不利。
    3. 创建一个Random 供整个应用程序使用,而不是每次随机播放(或单击某些内容)。并且永远不要在循环中创建它们 - 这几乎可以保证重复的数字。

    4. Random.Next(min, max) 的最大参数是独占,因此您的范围实际上比应有的小 1 个元素。

    5. 您的 Shuffle 非常接近,但有一些缺陷:
      • 一般来说,NET 版本的 Fisher-Yates Shuffle 是一个就地洗牌 (Sub),使其非常高效(而不是返回一个新集合)
      • 通过列表或数组循环向后很重要。1

    标准的 Fisher-Yates 洗牌:

    ' 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
    

    相同起始数组的 4 次随机播放的输出:

    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   
    

    变化

    您可以传递它而不是全局Random 生成器(作为扩展方法有用):

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

    改组许多类型的通用方法:

    ' 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
    

    例子:

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

    简单的重新排序

    最后,对于可能只重新排序一次的简单内容,使用扩展方法的简单且通常足够好的版本:

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

    这有更少的代码,很容易冲刺,但很多效率低下。

    1 之所以要向后循环,是为了将每个数组元素限制为 一个 交换。一旦在最后一步将“X”移动到items(j),该位置就不再考虑,因为rnd.Next(0, n + 1) 只会选择直到最后一个元素/循环索引。许多实现都犯了这个错误。

    【讨论】:

    • 伟大的解释,伟大的例子和伟大的人!谢谢!
    猜你喜欢
    • 2017-10-17
    • 1970-01-01
    • 2016-06-19
    • 2021-12-17
    • 2015-04-10
    • 2014-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多