Link to home
Start Free TrialLog in
Avatar of gonzal13
gonzal13Flag for United States of America

asked on

Randomize an array of numbers

Using the randomize statement and the RND function I can produce a set of random numbers. But what I actually need and have no idea how to do it, is to randomize a column of numbers.

For example If I have the following:
L = 10
X = 1
FOR Y = 1 TO L
     R(Y) = X
     X = X + 1
NEXT Y
Since I do not know how many numbers there will be, is the reason to use an Array and the variable 'L'.  Next I need to randomize the list in the array.

gonzal13(joe)
SOLUTION
Avatar of Jaime Olivares
Jaime Olivares
Flag of Peru image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Use the rnd() function to generate random numbers.  Here is a reference:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbenlr98/html/vafctrnd.asp
Avatar of gonzal13

ASKER

Jaime:

If I use a RND then there will be duplicate numbers with your program. Hopefully I interpreted this correctly.

Idle_Mind:

How in the world did you produce the code so fast? I am impressed! You have to do this for a living!

I will try it tonight. I assume that I will have to do several iterations to produce a fairly random list. I also assume that the list will not repeat? Also I need it to be an array, since I will access the numbers that will be about 400.

I guess that there is no way to use randomize and rnd to produce the list without duplications.

gonzal13(joe)
Idle_Mind

I was so excited that I did not realize that you had two programs. When you use the random function, it will not produce duplicate numbers?

gonzal13(Joe)
>If I use a RND then there will be duplicate numbers with your program. Hopefully I interpreted this correctly.
No, this is not correct, becuse I am not using RND to generate numbers, but just to change its order. Number generation is at the first for...next
>> How in the world did you produce the code so fast? I am impressed!
I had written this code awhile back for a PAQ.  =)

>> I assume that I will have to do several iterations to produce a fairly random list.
The code already shuffles the sequence seven times.

>> I also assume that the list will not repeat?
No.  I build the sequence and then shuffle it.

>> Also I need it to be an array...
The function returns an array in the form of a Variant.  The example shows how to iterate through it.

>> I was so excited that I did not realize that you had two programs
There is only one function there, generateSet(), along with an example of how to use it in Command1_Click().

My code is basically the same as the submission by jaime_olivares, but on steroids.

Regards,

Idle_Mind

Think of this algorithm as analagous to shuffling an actual deck of cards.  You already have all the possible values (cards) in your hand.  When you shuffle them, you are really swapping one cards position with another.

We are doing the same thing here.  First we create an array and fill it with all the possible values in the range.  This ensures that there are no duplicates.  Then for each position in the array, we pick another random position and swap the two values in those slots.  This is where the rnd() function comes in.  It is not generating one of the possible values, it is simply picking one of the possible slots to swap with.

Finally, we return only the number of values requested.  If this number is the same as the size of the range, then you have simply shuffled the entire set and returned it.  If the number of values requested is smaller than the range, then you have shuffled the entire range and picked the first X values.  This would be like shuffling a deck of cards and only pulling the first five cards off the top.

Regards,

Idle_Mind
Idle Mind:
I cannot see the array. I will look at Jaime's code also. I increased the points because of the service and the possibility of splitting the points.

gonzal13(Joe)
The array is declared inside the Command1_Click() sub:

    Private Sub Command1_Click()
        Dim i As Integer
        Dim selected As Variant                               ' <--- Array declared here
   
        ' pick 20 values from 1 to 100
        selected = generateSet(1, 100, 20)
        For i = LBound(selected) To UBound(selected)
            Debug.Print i & " = " & selected(i)
        Next i
    End Sub

It is declared as a variant because that is how you pass an array to/from a sub/function in Vb.  Try creating a new project and adding a button.  Then paste all of the code below my name from my first posting to see how it works.

Idle_Mind

I have to go play "store" with my daughter (6 yrs old) now or she is going to strangle me.  =)

I'll check back later to see how you are doing.

Idle_Mind
>Think of this algorithm as analagous to shuffling an actual deck of cards
That was a good explanation. It is exactly what algorithm does: 1st phase(for loop): "generate" the cards, 2nd phase: shuffle the cards.
Idle_Mind:
I will leave you a note in the lounge "what a wonderful life' . I have two grown children and fpor 15 years I was home only 6 months of the year.

Think of this algorithm as analagous to shuffling an actual deck of cards.

Interestingly when I was in my early thirties I used to be a blackjack card counter! I was caught several times in Las Vagas and in Lake Tajoe. I used to be able to count with 6 decks. I guess at that time I had a photographic memory. One must count using 'picturesof numbers' and not verbalize the mathematics.

Jaime:

¿Habla español?: Tengo 6 años en Mexico y 7 años en la escuela.
Do you speak Spanish I have worked in Mexico for 6 years and 67 years of formal education in the language. I also used to be a simultaneous translator when in Mexico along with being an engineering manager. We can visit in the Lounge under "What a wonderful life"  

Now to study the various methods. I need to go back in the winter to start VB.Net

Ps I am of Russian extraction, first generation.


gonzal13(joe)



I added points for the wonderful explanations that you both supplied.

When I first posted questions I would not get quick responses.

Two  questions were based on two assignments. It was inconvenient for me to travel 20 miles to ask a question. He would not accept e-mails! Also the teacher converted one of the two class periods to lab time! He had no enthusiasm since it was the last semester on VB6. I felt robbed!

Anyway this is more fun than CHess!

gonzal13(Joe)
Out of curiosity, would not one also use at the beginning the Randomize statement to provide a pure random function based on the system clock. I realize that even in shuffling cards, one does not get a pure random shuffle. Just a comment, not really important. Somewhere I read that using the RND statement one will eventually run into a repetetive cycle.

gonzal13(Joe)
Hola, si hablo español, soy peruano, aunque aqui en E-E es una obligacion hablar en ingles, lo cual me ha traido malos entendidos mas de una vez.

About randomize, you can use it, but it is not certain to have a good random secuence. If you are interested in true random numbers, you can investigate in different methods like hearing noise from the microphone input.
Also you can shuffle your array many times, as I told you earlier.

Buena suerte,
Jaime.
Jaime:

My masters degree was in International Management from Thunderbird Graduate School of International Management.

One need an A average to graduate. Anyway when I was taking advanced Spanish I had trouble rolling the Rs. My teacher said I would get a C if I did not succeed. Well I started in my dorm room practicing outloud. People complained and I had to go to the parking lot and practice in my car. This lasted 6 months. Got my A!

gonzal13(joe)
Jaime:

The following for some reason gives me consectutive numbers

Dim R(400)
L = 10
For Y = 1 To L
   pos = Rnd() * (L - 1) + 1 '  RANDOM NUMBER FROM 1 TO L
   temp = R(pos)
   R(pos) = R(Y)
   R(Y) = temp
Print Y
Next Y

End Sub

gonzal13(Joe)
Your printing function must be after suffling:

Dim R(400)
L = 10
For Y = 1 To L
   pos = Rnd() * (L - 1) + 1 '  RANDOM NUMBER FROM 1 TO L
   temp = R(pos)
   R(pos) = R(Y)
   R(Y) = temp
   ' DO NOT PRINT WHILE SHUFFLING
Next Y

For Y = 1 To L
    PRINT R(Y)    ' THE CORRECT EXPRESSION IS R(Y) BECAUSE Y IS ALWAYS ORDERED
Next Y

End Sub
>> Out of curiosity, would not one also use at the beginning the Randomize statement to provide a pure random function based on the system clock.

You are right.  Usually you pick a random seed when the app starts like this:

    Private Sub Form_Load()
        Randomize Timer
    End Sub

If you don't, then the same "random" sequence will be used everytime you run the app.  These are not truly random numbers, but for most applications they are fine.

Idle_Mind
Jaime:

See the notes next to the code.

Private Sub mnuShuffleJaime_Click()

Dim r(400)
L = 10
For Y = 1 To L
   pos = Rnd() * (L - 1) + 1 '  RANDOM NUMBER FROM 1 TO L
   temp = r(pos)
   r(pos) = r(Y)
   r(Y) = temp
   Print r(Y)
Next Y

For Y = 1 To L
    Print r(Y)    ' THE CORRECT EXPRESSION IS R(Y) BECAUSE Y IS ALWAYS ORDERED
Next Y

           'INTERESTING ENOUGH THAT THE PRINT COMMANDS WILL NOT PRINT
           'ON THE TEMPLATE NOW! I CLOSED VB6 AND REOPENED THE PROGRAM.
           'I tried another program and it printed.


End Sub

IdleMind:

See notes in the code

Private Sub mnuShuffle2IdleMind_Click()
    'Dim generateSet(ByVal rangeMin As Integer, ByVal rangeMax As Integer, ByVal setSize As Integer) As Variant
                                   'Note Added DIM and received "expected Expression, compile error
     Dim rangesize As Integer
    Dim rangeSet() As Integer
---------------------------------------------------------------------
Private Sub mnuShuffle1IdleMind_Click()
     Dim i As Integer
    Dim GenerateSet(1, 800, 400) 'ADDED
    Dim selected As Variant
   
    ' pick 20 values from 1 to 100
    selected = GenerateSet(1, 100, 20)
    For i = LBound(selected) To UBound(selected)           'TYPE MISMATCH
        Print i & " = " & selected(i)
    Next i
End Sub    

gonzal13
Private Sub mnuShuffle1IdleMind_Click()
     Dim i As Integer
    ' Dim GenerateSet(1, 800, 400) 'ADDED     <---- Take this line out
    Dim selected As Variant
   
    ' This will pick 400 random values from the range 1 to 800
    selected = GenerateSet(1, 800, 400)
    For i = LBound(selected) To UBound(selected)           ' No more TYPE MISMATCH  <-------
        Print i & " = " & selected(i)
    Next i
End Sub    
Idle-Mind:
Removed the "Dim" and the following resulted.

Sub or function not defined
selected = GenerateSet(1, 100, 20)

gonzal13(Joe)
=)

You need the GenerateSet() function on your form as well:

Private Function generateSet(ByVal rangeMin As Integer, ByVal rangeMax As Integer, ByVal setSize As Integer) As Variant
    Dim rangesize As Integer
    Dim rangeSet() As Integer
   
    Dim i As Integer
    Dim r As Byte
    Dim swapWith As Integer
    Dim tempInt As Integer
   
    ' compute the size of the range
    rangesize = rangeMax - rangeMin + 1
   
    ' make sure the input parameters make sense...
    If rangeMax < rangeMin Then
        MsgBox "rangeMax must be greater than or equal to rangeMin"
        Exit Function
    End If
    If setSize <= 0 Or setSize > rangesize Then
        MsgBox "setsize must be greater than zero and less than or equal to the range size"
        Exit Function
    End If
   
    ' resize our array
    ReDim rangeSet(rangesize - 1)
   
    ' build the range set
    For i = 0 To rangesize - 1
        rangeSet(i) = i + rangeMin
    Next i
   
    ' shuffle the range set 7 times
    For r = 1 To 7
        ' for each item in the set,
        ' pick another item and
        ' swap them
        For i = 0 To rangesize - 1
            swapWith = Int(rangesize * Rnd)
            tempInt = rangeSet(i)
            rangeSet(i) = rangeSet(swapWith)
            rangeSet(swapWith) = tempInt
        Next i
    Next r
                 
    ' return the selected set
    ReDim Preserve rangeSet(setSize - 1)
    generateSet = rangeSet
End Function
I increased the points for additional information

Idle_Mind

Form
Tools
Add Procedure
      Generateset
      Function option
      Private
Made a private function procedure
Private Function generateset(ByVal rangeMin As Integer, ByVal rangeMax As Integer, ByVal setSize As Integer) As Variant
    Dim rangesize As Integer
    Dim rangeSet() As Integer
-
-
-
-
.
End Function

Made an event procedure

Private Sub mnuShuffleIdleMind_Click()
      ????????
End sub

I do not know how to Call the procedure.

I tried to use the CallbyName but the format I have is incorrect, since I do not know how to define the object
Idle_Mind

Out of curiosity why did you make the program a function instead of a click event?

gonzal13(Joe)
Hi Joe,

All you need to do is copy the generateSet() function, in its entirety, and then paste it in your form code somewhere.  I made generateSet() a function because it is generic and can be used over and over from different points in your code.  If you embed all that code in an event such as mnuShuffle1IdleMind_Click() then it is harder to resuse it elsewhere in your application.

Regards,

Idle_Mind

Private Sub mnuShuffle1IdleMind_Click()
    Dim i As Integer
    Dim selected As Variant
   
    ' This will pick 400 random values from the range 1 to 800
    selected = GenerateSet(1, 800, 400)
    For i = LBound(selected) To UBound(selected)
        Print i & " = " & selected(i)
    Next i
End Sub    

Private Function generateSet(ByVal rangeMin As Integer, ByVal rangeMax As Integer, ByVal setSize As Integer) As Variant
    Dim rangesize As Integer
    Dim rangeSet() As Integer
   
    Dim i As Integer
    Dim r As Byte
    Dim swapWith As Integer
    Dim tempInt As Integer
   
    ' compute the size of the range
    rangesize = rangeMax - rangeMin + 1
   
    ' make sure the input parameters make sense...
    If rangeMax < rangeMin Then
        MsgBox "rangeMax must be greater than or equal to rangeMin"
        Exit Function
    End If
    If setSize <= 0 Or setSize > rangesize Then
        MsgBox "setsize must be greater than zero and less than or equal to the range size"
        Exit Function
    End If
   
    ' resize our array
    ReDim rangeSet(rangesize - 1)
   
    ' build the range set
    For i = 0 To rangesize - 1
        rangeSet(i) = i + rangeMin
    Next i
   
    ' shuffle the range set 7 times
    For r = 1 To 7
        ' for each item in the set,
        ' pick another item and
        ' swap them
        For i = 0 To rangesize - 1
            swapWith = Int(rangesize * Rnd)
            tempInt = rangeSet(i)
            rangeSet(i) = rangeSet(swapWith)
            rangeSet(swapWith) = tempInt
        Next i
    Next r
                 
    ' return the selected set
    ReDim Preserve rangeSet(setSize - 1)
    generateSet = rangeSet
End Function
Idle_Mind:
I rearranged it to be a click event, but nothing happens?

Private Sub mnuShuffleIdleMind_Click()
    Dim rangemin As Integer
    Dim rangemax As Integer
    Dim setsize As Integer
    Dim rangesize As Integer
    Dim rangeSet() As Variant
    Dim generateset As Variant
    Dim i As Integer
    Dim r As Byte
    Dim swapWith As Integer
    Dim tempInt As Integer

        ' compute the size of the range
    rangemax = 104
    rangemin = 52
    setsize = 52
    rangesize = rangemax - rangemin + 1
   
    ' make sure the input parameters make sense...
    If rangemax < rangemin Then
        MsgBox "rangeMax must be greater than or equal to rangeMin"
                     ' Exit Function
    End If
    If setsize <= 0 Or setsize > rangesize Then
        MsgBox "setsize must be greater than zero and less than or equal to the range size"
                    ' Exit Function
    End If
Try it like I showed in my last post and see if it works.

Just copy both mnuShuffle1IdleMind_Click() and generateSet() at the same time, then paste them over your previous mnuShuffle1IdleMind_Click() code.

Idle_Mind
Jaime:
Descúlpame, cuando revisí su idea, no puse la siguiente 4 lineas.

L = 10
FOR Y = 1 TO L
     R(Y) = Y
NEXT Y


Leí en un libro, cuando se lo usa rnd, la tendencía es de repitir el resultado.
Entonses. agragué la siguiente: “Randomize” También, soy un engieniero, entónces me encanta
soluciones muy complicadas.  Es un opurtunidad de aprender un nuevo tema..

Por casualidad, si tengas interés en un programa que se puede agregar la siguiente:
Á é í ñ ó ú ! ¡ ? ¿, pasa a ‘It is a wonderful life, y si lo permite el conservidor de sitio, dejame su e-mail. Entonces lo mando el programa.Es simple de implementar.

Tambíen decidí usar su idea. Por este monemto,  mi experiencía no es muy amplía con VB



Translation for Idle_Mind:

First of all I will use Jaime's solution since my experience with VB is limited at this moment.

Jaime: Please excuse me, but when I tried to use your program, I forgot to add the four following lines:

I read in a book, where it stated, and I mentioned this, that rnd, produces over an unknown perion of time the same sets of numbers. I thus added “Randomize” Also I am an engineer, and thus by nature I love complicated solutions. It is an opportunity to learn something new that Idle_Mind was so patient to teach me.

Oh, if you have an interest to have a tool bar for accent marks etc, meet me at ‘It is a wonderful world” and if the moderator will permit it, leave your e-mail address. I will send you the program. It is easy to use.

I would like to split evenly the points.

Idle_Mind, I am still interested in your solution as a matter of learning something new. Still would like to know " what is Object" when I call the function. Also cannot see the Array.

Oh, in the the 4 years on this website,as a commentator 1/2 of it in Win 98,I have never had the need to split points for a question I had presented. How is this done?

gonzal13(joe)


Oh, just noticed the "SPLIT" option.

gonzal13(Joe)
gonzal13,
Thanks for the points.
my e-mail is in my profile, just click at my name link.
It is a bit confusing to split points, look at the end of the page, just above where you write the comments, there is a little textual  hyperlink "Split points", not a button like in "Accept".
Buena suerte y nos vemos en la siguiente pregunta.
Jaime.
>> Still would like to know " what is Object" when I call the function. Also cannot see the Array.

Alrighty, one more shot at trying to explain it.

 =)

Create a new project and add a button.  Paste the code below into the form, as it is.  The "selected" variable has been declared as a Variant.  This means that it can basically hold anything (similar to object).  After the call to generateSet(), the "selected" variable will be holding an array of integers.  The For...Next loop just below that call shows how to get to every item in the array.  The generateSet() function returns the created array via the Variant return type.

Please feel free to continue posting in the thread with questions you have about the code I submitted.  I would really like for you to understand how it works.

Regards,

Idle_Mind

' -----------------------------
' Form1
' -----------------------------
Option Explicit

Private Sub Command1_Click()
    Dim i As Integer
    Dim selected As Variant
   
    ' pick 20 values from 1 to 100
    selected = generateSet(1, 100, 20)
    For i = LBound(selected) To UBound(selected)
        Debug.Print i & " = " & selected(i)
    Next i
End Sub

Private Function generateSet(ByVal rangeMin As Integer, ByVal rangeMax As Integer, ByVal setSize As Integer) As Variant
    Dim rangesize As Integer
    Dim rangeSet() As Integer
   
    Dim i As Integer
    Dim r As Byte
    Dim swapWith As Integer
    Dim tempInt As Integer
   
    ' compute the size of the range
    rangesize = rangeMax - rangeMin + 1
   
    ' make sure the input parameters make sense...
    If rangeMax < rangeMin Then
        MsgBox "rangeMax must be greater than or equal to rangeMin"
        Exit Function
    End If
    If setSize <= 0 Or setSize > rangesize Then
        MsgBox "setsize must be greater than zero and less than or equal to the range size"
        Exit Function
    End If
   
    ' resize our array
    ReDim rangeSet(rangesize - 1)
   
    ' build the range set
    For i = 0 To rangesize - 1
        rangeSet(i) = i + rangeMin
    Next i
   
    ' shuffle the range set 7 times
    For r = 1 To 7
        ' for each item in the set,
        ' pick another item and
        ' swap them
        For i = 0 To rangesize - 1
            swapWith = Int(rangesize * Rnd)
            tempInt = rangeSet(i)
            rangeSet(i) = rangeSet(swapWith)
            rangeSet(swapWith) = tempInt
        Next i
    Next r
                 
    ' return the selected set
    ReDim Preserve rangeSet(setSize - 1)
    generateSet = rangeSet
End Function
Idle_Mind

thanks:

I will enthusiasically make an effort to understand it. As an engineer I am accustomed to always working out of my comfort zone.

Joe