Results 1 to 10 of 10

Thread: Randomising (an array) without repeats VB.net

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Sep 2018
    Posts
    20

    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.

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    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.

  3. #3
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    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

  4. #4
    Powered By Medtronic dbasnett's Avatar
    Join Date
    Dec 2007
    Location
    Jefferson City, MO
    Posts
    9,764

    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
    My First Computer -- Documentation Link (RT?M) -- Using the Debugger -- Prime Number Sieve
    Counting Bits -- Subnet Calculator -- UI Guidelines -- >> SerialPort Answer <<

    "Those who use Application.DoEvents have no idea what it does and those who know what it does never use it." John Wein

  5. #5
    eXtreme Programmer .paul.'s Avatar
    Join Date
    May 2007
    Location
    Chelmsford UK
    Posts
    25,481

    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...

  6. #6
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Randomising (an array) without repeats VB.net

    Quote Originally Posted by .paul. View Post
    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.

  7. #7
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    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

  8. #8
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Randomising (an array) without repeats VB.net

    Quote Originally Posted by boops boops View Post
    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.

  9. #9

  10. #10
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,350

    Re: Randomising (an array) without repeats VB.net

    Quote Originally Posted by boops boops View Post
    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
  •  



Click Here to Expand Forum to Full Width