【问题标题】:VB.NET Random unique generatorVB.NET 随机唯一生成器
【发布时间】:2019-01-12 02:34:38
【问题描述】:

我正在尝试使用下面的代码的 sn-p 生成一个唯一的随机数生成器,但它不起作用。 IF部分假设测试它是否是第一个生成的随机数,如果是,则假设将第一个随机数添加到ArrayList,如果它不是第一个随机数,则应该检查随机数是否已经在ArrayList,如果它在 ArrayList 中,它假设 MsgBox 并生成一个新的唯一随机数,该随机数不在 ArrayList 中并将其添加到 ArrayList,但它没有做任何这些。任何帮助将不胜感激。

Public Class Form1
    Dim r As New Random
    Dim dLowestVal As Integer = 1
    Dim dHighestVal As Integer = 26
    Dim dItemAmount As Integer = 1
    Dim RollCheck As New HashSet(Of Integer)

    Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
        End
    End Sub

    Private Sub btnRollDice_Click(sender As Object, e As EventArgs) Handles btnRollDice.Click
        lblRandomNo.Text = r.Next(dLowestVal, dHighestVal)

        lblItemAmount.Text = dItemAmount

        If dItemAmount = 1 Then
            RollCheck.Add(Val(lblRandomNo.Text))
        ElseIf (RollCheck.Contains(Val(lblRandomNo.Text))) Then
            MsgBox("Already Exists")
            lblRandomNo.Text = r.Next(dLowestVal, dHighestVal)
            RollCheck.Add(Val(lblRandomNo.Text))
        End If

        dItemAmount = dItemAmount + 1

提前致谢。

【问题讨论】:

  • Dim dItemAmount as Integer = 1, dItemAmount = dItemAmount + 1 在达到If dItemAmount = 1 Then 之前会变成2,不是吗?那么你的ElseIf 将永远不会触发,因为RollCheck 可能是空的。设置断点,使用调试器。
  • 在检查 Contains 后,您再次调用 r,Next 但您可以再次获得数组中已经存在的数字
  • ArraryLists 已经过时了一段时间(不是正式的,而是实践方面的)。请改用List(Of Integer),甚至更好:HashSet(Of Integer),它更快且不允许重复。此外,如果您尝试添加的项目已经存在,HashSet.Add() method 将返回 False。
  • 这段代码有很多问题,老实说:1) dItemAmount 在你做任何事情之前就会变成 2。 2) 您的ElseIf 仅在您生成的号码之前已生成并保存到列表中时才会触发。 3)正如@Steve 所说,您可以在列表中生成一个数字。 4) 你无法在第一次运行后生成一个数字,除非你点击列表中已经存在的一个(以便它进入你的ElseIf)然后生成一个新的。
  • 更简单的选择是对数组进行洗牌,然后从其中一个一个地获取值stackoverflow.com/questions/254844/…

标签: vb.net


【解决方案1】:

您可以用这个简单的方法替换整个方法

' This is globally declared at the top of your form
Dim values As New List(Of Integer)

' This is called when you construct your form
' It will store consecutive integers from 1 to 25 (25 elements)
values = Enumerable.Range(1, 25).ToList()

这是从您的值中提取尚未使用的整数的方法

Private Sub Roll()
    ' Get an index in the values list
    Dim v = r.Next(0, values.Count)

    ' insert the value at that index to your RollCheck HashSet
    RollCheck.Add(values(v))

    ' Remove the found value from the values list, so the next call 
    ' cannot retrieve it again. 
    values.Remove(values(v))
End Sub

而且你可以通过这种方式从之前的事件处理程序中调用它

Private Sub btnRollDice_Click(sender As Object, e As EventArgs) Handles btnRollDice.Click
  if values.Count = 0 Then
      MessageBox("No more roll available")
  else
      Roll()
  End Sub
End Sub

【讨论】:

    【解决方案2】:

    HashSet 的要点在于,由于它不允许重复,因此您只需检查Add() 的返回值即可确定该数字是否已成功插入或是否已存在于列表中。

    如果你想继续尝试直到成功,你所要做的就是将它包装在一个循环中:

    If dHighestVal - dLowestVal >= RollCheck.Count Then
        'If the above check passes all unique values are MOST LIKELY already in the list. Exit to avoid infinite loop.
        MessageBox.Show("List is full!")
        Return 'Do not continue.
    End If
    
    Dim Num As Integer = r.Next(dLowestVal, dHighestVal)
    
    'Iterate until a unique number was generated.
    While Not RollCheck.Add(Num)
        MessageBox.Show("Already exists!")
        Num = r.Next(dLowestVal, dHighestVal)
    End While
    
    lblRandomNo.Text = Num
    

    另一种编写循环的方法是:While RollCheck.Add(Num) = False。

    【讨论】:

    • 感谢 Visual Vincent,您提供的解决方案完全符合我的要求。再次感谢你。非常感谢。
    • @user3289583 :很高兴我能帮上忙!祝你的项目好运!
    • 此代码会生成最高值吗?调用r.Next时,第二个参数是exclusive,所以你需要使用dHighestVal + 1。
    • @ChrisDunaway :没错,但这一切都归结为 OP 的代码如何工作/他希望它如何工作。我刚刚将我的解决方案改编为原始代码。
    猜你喜欢
    • 2013-03-13
    • 1970-01-01
    • 2018-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-27
    • 2011-08-19
    • 2012-12-29
    相关资源
    最近更新 更多