-
Jan 12th, 2020, 04:11 PM
#1
Thread Starter
Junior Member
Randomising (an array) without repeats VB.net
I hope it's okay to post a solution without a query!
Last week, I wanted to randomise the order of an array (of FileInfo that defaults to numero-alpha order), so needed a way of generating random index numbers without repeating any. I couldn't find a very good solution online so came up with this. I thought it's pretty good (though no doubt could be more elegantly written), so wanted to share it somewhere should it help somebody sometime.
**************************************************************************************************** ********
To randomise the order of the items in an array (or similar).
Create a list the same length as the array and populate it with the numbers of indexes i.e. index(0)=0, index(1)=1 etc
Derive a random number then use that number to draw another number from the list – use it before removing it from the list.
This means we can have repeated random numbers, but the numbers actually used cannot be repeated.
For example:
(0) = 0; (1) = 1; (2) = 2; (3) = 3
2 is picked at random (from the range 0 to 3) so copy item 2 (number 2) from the array and put it into item 0. Delete item 2.
Now:
(0) = 0; (1)=1; (2)=3
2 is picked at random again (from the range 0 to 2), so copy item 2 (number 3) from the array and put it into item 1. Delete item 2.
Now:
(0) = 0; (1)=1
0 is picked at random (from the range 0 to 1), so copy item 0 (number 0) from the array and put it into item 2. Delete item 0.
Etc.
**************************************************************************************************** ********
Code:
Private Sub shuffle_Arr()
Dim i As Integer = myArray.Length - 1 'how big the global array is
Dim tmp_List As New List(Of Integer)(i) 'a temporary list for random numbers
Dim myArray_2(i) 'a temporary array to cache the random items
Dim rnum As Integer = 0 'each random number
Dim tmpRnd As Integer = 0 'the number taken from the array randomly
Dim temp As FileInfo 'temporary item of whatever type
Dim s As Integer = 0 'to count with
Dim g As Integer = 0 'to count with
While s <= 9 'populate the list with the number of its reference i.e. f(0) = 0, f(1) = 1 etc
tmp_List.Add(s)
s += 1 's counts up to the length of the list
End While
s -= 1 's is now list length -1
For Each f In myArray 'a global array
rnum = genRand(0, s) 'random number is 0 to size of list of numbers (and array)
tmpRnd = tmp_List(rnum) 'grab a number at random.
temp = myArray(tmpRnd) 'temp is randomly taken from the array
myArray_2(g) = temp 'populate temporary array from 0 up
tmp_List.RemoveAt(rnum) 'remove the used number – this can be done with a list. This means that the index can be repeated, but the items against the indexes are unique.
g += 1 'count up through myArray_2
s = s - 1 'count down as we loop round
Next
ReDim myArray(i + 1) 'clear the array
myArray = myArray_2.Clone 'clone it from the randomised version.
End Sub
Private Function genRand(min As Int32, max As Int32) As Int32
Static rnum2 As New Random
Return rnum2.Next(min, max + 1)
End Function
Last edited by Shaggy Hiker; Jan 13th, 2020 at 03:01 PM.
Reason: Added CODE tags.
-
Jan 12th, 2020, 05:01 PM
#2
Re: Randomising (an array) without repeats VB.net
Follow the CodeBank link in my signature below and you'll find two threads about randomising lists.
For future reference, please don't post unformatted code snippets as they are too hard to read. There are two buttons even on the simplest editor toolbar to format code so please make use of them.
-
Jan 13th, 2020, 10:00 AM
#3
Re: Randomising (an array) without repeats VB.net
Your code looks a little long-winded. Try this...
Code:
Public Class Form1
Dim r As New Random
Dim numbers As List(Of Integer)
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
numbers = New List(Of Integer)(Enumerable.Range(0, NumericUpDown1.Value).ToArray)
Button2.Enabled = True
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim i As Integer = r.Next(0, numbers.Count)
Dim n As Integer = numbers(i)
numbers.RemoveAt(i)
If numbers.Count = 0 Then Button2.Enabled = False
MsgBox(n)
End Sub
End Class
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Jan 13th, 2020, 01:11 PM
#4
Re: Randomising (an array) without repeats VB.net
$0.02
Code:
Static prng As New Random
Dim pth As String
pth = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Dim di As New IO.DirectoryInfo(pth)
Dim dataIn As List(Of IO.FileInfo) = di.GetFiles.ToList
'create a random list of indicies
Dim randIDXs As List(Of Integer)
Const NumDataOut As Integer = 9 'number of output items
randIDXs = Enumerable.Range(0, dataIn.Count).OrderBy(Function(n) prng.Next(0, dataIn.Count)).Take(NumDataOut).ToList
Dim dataOut As New List(Of IO.FileInfo) 'random output
For Each i As Integer In randIDXs 'create the random output
dataOut.Add(dataIn(i))
Next
Stop 'look at dataIn and dataOut
-
Jan 13th, 2020, 01:33 PM
#5
Re: Randomising (an array) without repeats VB.net
Arrays are arrays. With an array (It’s easier with a generic List) of FileInfo, you have two options for avoiding selecting duplicates. You can remove them from the collection, or you can add them to a second collection that you use as an exclude list. On selecting a random FileInfo, you can check it doesn’t exist in your exclude list, if not use it and add it to the exclude list, else pick another random FileInfo and try again...
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Jan 13th, 2020, 06:21 PM
#6
Re: Randomising (an array) without repeats VB.net
Originally Posted by .paul.
Arrays are arrays. With an array (It’s easier with a generic List) of FileInfo, you have two options for avoiding selecting duplicates. You can remove them from the collection, or you can add them to a second collection that you use as an exclude list. On selecting a random FileInfo, you can check it doesn’t exist in your exclude list, if not use it and add it to the exclude list, else pick another random FileInfo and try again...
I'd suggest that, if you want items one by one, the "most correct" solution would be to randomise whatever list you have using OrderBy and a Random object and create a Queue from the result. You can then dequeue items from that randomised Queue as required.
-
Jan 16th, 2020, 05:15 PM
#7
Re: Randomising (an array) without repeats VB.net
Concise is nice. So are Queues but I prefer a Stack: after all, who wants to Dequeue something when you can just as easily Pop it?
So here's how I would code it, assuming we start with an array of Thing called MyThings.
Code:
'Load the array randomly into a Generic Stack:
Dim rnd As New Random
Dim stk As New Stack(Of Thing) (MyThings.Distinct.OrderBy(Function() rnd.Next))
'Get an item from the Stack:
If stk.Count>0 Then Console.WriteLine(stk.Pop.ToString)
Pop automatically removes the first item from the Stack, so there is no need to delete items as you would from a List (which can be quite troublesome in a loop). The Distinct function is a precaution if there's a possibility that the original array contains multiple copies of a given item. Otherwise you could leave it out.
BB
Last edited by boops boops; Jan 16th, 2020 at 05:26 PM.
-
Jan 16th, 2020, 05:37 PM
#8
Re: Randomising (an array) without repeats VB.net
Originally Posted by boops boops
I prefer a Stack: after all, who wants to Dequeue something when you can just as easily Pop it?
I'm sure that you know this already but, for those who don't, the two are effectively identical in this scenario. A Queue is FIFO while a Stack is LIFO but both will give you the items in a list one by one while removing them, so both do the same thing if you're not adding items after initialisation and don't care what end you start at. If you were simulating a card game and wanted a discard pile then you'd definitely use a Stack for that. To me, a Queue feels more natural and I only use a Stack in situations where I specifically need LIFO functionality but that's just personal preference. Using a Stack by default and a Queue only when it's needed is just as legitimate.
-
Jan 16th, 2020, 05:49 PM
#9
Re: Randomising (an array) without repeats VB.net
A stack's my personal preference because the word "Dequeue" is harder to spell than "Pop". It's so tinny BB
-
Jan 16th, 2020, 07:21 PM
#10
Re: Randomising (an array) without repeats VB.net
Originally Posted by boops boops
A stack's my personal preference because the word "Dequeue" is harder to spell than "Pop". It's so tinny BB
If only VS included some magic technology that meant that you didn't have to spell the names of types or members yourself and it would make suggestions and fill them in for you.
Tags for this Thread
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|