vb.net 数组中的随机数没有任何重复

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17666175/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 14:16:23  来源:igfitidea点击:

Random numbers in array without any duplicates

vb.netloops

提问by user2472706

I'm trying to randomize an array from numbers 0 to 51 using loops but I just cannot seem to pull it off. My idea was that

我正在尝试使用循环从数字 0 到 51 随机化一个数组,但我似乎无法将其拉下来。我的想法是

  1. Generate a Random Number
  2. Check if this random number has been used by storing the previous in an array
  3. If this random number has been used, generate new random number until it is not a duplicate
  4. If it's not a duplicate, store it
  1. 生成随机数
  2. 通过将前一个存储在数组中来检查此随机数是否已被使用
  3. 如果此随机数已被使用,则生成新的随机数,直到不重复为止
  4. 如果它不是重复的,则存储它

My attempt:

我的尝试:

    Dim list(51) As Integer
    Dim templist(51) As Integer

    For i As Integer = 0 To 51 Step 1
        list(i) = i
    Next i

    Do While counter <= 51
        p = rand.Next(0, 52)
        templist(counter) = p
        For n As Integer = 0 To 51 Step 1
            p = rand.Next(0, 52)
            If templist(n) = p Then
                Do While templist(n) = p
                    p = rand.Next(0, 52)
                Loop
                templist(n) = p
            Else
                templist(n) = p
            End If

        Next

        counter += 1
    Loop

    For n As Integer = 0 To 51 Step 1
        ListBox1.Items.Add(templist(n))
    Next

回答by Douglas Barbin

It will be a lot easier if you just have a list of all of the possible numbers (0 to 51 in your case), then remove the number from the list so it can't be picked again. Try something like this:

如果您只有一个所有可能数字的列表(在您的情况下为 0 到 51),然后从列表中删除该数字,这样就无法再次选择它,那将会容易得多。尝试这样的事情:

Dim allNumbers As New List (Of Integer)
Dim randomNumbers As New List (Of Integer)
Dim rand as New Random

' Fill the list of all numbers
For i As Integer = 0 To 51 Step 1
    allNumbers.Add(i)
Next i

' Grab a random entry from the list of all numbers
For i As Integer = 0 To 51 Step 1
    Dim selectedIndex as Integer = rand.Next(0, (allNumbers.Count - 1) )
    Dim selectedNumber as Integer = allNumbers(selectedIndex)
    randomNumbers.Add(selectedNumber)
    allNumbers.Remove(selectedNumber)
    ' Might as well just add the number to ListBox1 here, too
    ListBox1.Items.Add(selectedNumber)
Next i

If your goal is to get the numbers into ListBox1, then you don't even need the "randomNumbers" list.

如果您的目标是将数字放入 ListBox1,那么您甚至不需要“randomNumbers”列表。

EDIT:

编辑:

If you must have an array, try something like this:

如果您必须有一个数组,请尝试以下操作:

Function RandomArray(min As Integer, max As Integer) As Integer()

    If min >= max Then
        Throw New Exception("Min. must be less than Max.)")
    End If

    Dim count As Integer = (max - min)
    Dim randomNumbers(count) As Integer
    Dim rand As New Random()

    ' Since an array of integers sets every number to zero, and zero is possibly within our min/max range (0-51 here),
    ' we have to initialize every number in the array to something that is outside our min/max range.
    If min <= 0 AndAlso max >= 0 Then
        For i As Integer = 0 To count
            randomNumbers(i) = (min - 1)    ' Could also be max + 1
        Next i
    End If

    Dim counter As Integer = 0
    ' Loop until the array has count # of elements (so counter will be equal to count + 1, since it is incremented AFTER we place a number in the array)
    Do Until counter = count + 1
        Dim someNumber As Integer = rand.Next(min, max + 1)
        ' Only add the number if it is not already in the array
        If Not randomNumbers.Contains(someNumber) Then
            randomNumbers(counter) = someNumber
            counter += 1
        End If
    Loop

    Return randomNumbers
End Function

This is good enough for your assignment, but the computer scientist in my hates this algorithm.

这对于你的任务来说已经足够了,但是我的计算机科学家讨厌这个算法。

Here's why this algorithm is much less desirable. If zero is in your range of numbers, you will have to loop through the array at least 2N times (so 104+ times if you are going from 0 to 51). This is a best case scenario; the time complexity of this algorithm actually gets worse as the range of numbers scales higher. If you try running it from 0 to 100,000 for example, it will fill the first few thousand numbers very quickly, but as it goes on, it will take longer and longer to find a number that isn't already in the list. By the time you get to the last few numbers, you could potentially have randomly generated a few trillion different numbers before you find those last few numbers. If you assume an average complexity of 100000! (100,000 factorial), then the loop is going to execute almost ten to the half-a-millionth power times.

这就是为什么这个算法不太受欢迎的原因。如果零在您的数字范围内,您将必须至少循环数组 2N 次(如果您从 0 到 51,则为 104+ 次)。这是最好的情况;随着数字范围的扩大,该算法的时间复杂度实际上变得更糟。例如,如果您尝试从 0 到 100,000 运行它,它将很快填充前几千个数字,但随着它的进行,找到不在列表中的数字将花费越来越长的时间。到最后几个数字时,在找到最后几个数字之前,您可能已经随机生成了几万亿个不同的数字。如果您假设平均复杂度为 100000!(100,000 阶乘),那么循环将执行近十到百万分之一次幂次。

An array is more difficult to "shuffle" because it is a fixed size, so you can't really add and remove items like you can with a list or collection. What you CAN do, though, is fill the array with your numbers in order, then go through a random number of iterations where you randomly swap the positions of two numbers.

数组更难“洗牌”,因为它是固定大小,因此您无法像使用列表或集合那样真正添加和删除项目。但是,您可以做的是按顺序用您的数字填充数组,然后进行随机次数的迭代,您随机交换两个数字的位置。

回答by Samuel Adam

Do While counter <= 51
            p = rand.Next(0, 52)

            While Array.IndexOf(list, p) = -1
                p = rand.Next(0, 52)
            End While

            counter += 1
        Loop

回答by David Sherret

Haven't written VB in about 5 years, but try this out:

大约 5 年没有写过 VB,但试试这个:

Function GetRandomUniqueNumbersList(ByVal fromNumber As Integer, ByVal toNumber As Integer) As List(Of Integer)
    If (toNumber <= fromNumber) Then
        Throw New ArgumentException("toNumber must be greater than fromNumber", toNumber)
    End If
    Dim random As New Random
    Dim randomNumbers As New HashSet(Of Integer)()
    Do
        randomNumbers.Add(random.Next(fromNumber, toNumber))
    Loop While (randomNumbers.Count < toNumber - fromNumber)
    Return randomNumbers.ToList()
End Function

Ok, that was painful. Please someone correct it if I made any mistakes. Should be very quick because it's using a HashSet.

好吧,那很痛苦。如果我犯了任何错误,请有人纠正。应该很快,因为它使用的是 HashSet。

回答by rellis

First response to forum on stackoverflow - be gentle. I was looking for a way to do this but couldn't find a suitable example online. I've had a go myself and eventually got this to work:

对 stackoverflow 论坛的第一反应 - 保持温和。我正在寻找一种方法来做到这一点,但在网上找不到合适的例子。我自己试了一下,最终让它起作用:

Sub addUnique(ByRef tempList, ByVal n, ByRef s)
    Dim rand = CInt(Rnd() * 15) + 1
    For j = 0 To n
        If tempList(j) = rand Then
            s = True
        End If
    Next
    If s = False Then
        tempList(n) = rand
    Else
        s = False
        addUnique(tempList, n, s)
    End If
End Sub

Then call the sub using:

然后调用子使用:

Dim values(15) As Byte
Dim valueSeen As Boolean = False
For i = 0 To 15
    addUnique(values, i, valueSeen)
Next

This will randomly add the numbers 1 to 16 into an array. Each time a value is added, the previous values in the array are checked and if any of them are the same as the randomly generated value, s is set to true. If a value is not found (s=false), then the randomly generated value is added. The sub is recursively called again if s is still true at the end of the 'For' loop. Probably need 'Randomize()' in there somewhere.

这会将数字 1 到 16 随机添加到数组中。每次添加一个值时,都会检查数组中先前的值,如果其中任何一个值与随机生成的值相同,则将 s 设置为 true。如果未找到值 (s=false),则添加随机生成的值。如果 s 在 'For' 循环结束时仍然为真,则再次递归调用 sub。可能需要在某处使用 'Randomize()'。

Apologies if layout is a bit wobbly.

如果布局有点不稳定,请见谅。