Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Random Number Array - Each Value Once 3

Status
Not open for further replies.

mwolf00

Programmer
Nov 5, 2001
4,177
0
0
US
I am trying to create an array of random numbers - with values between 0 and 188. I want the numbers ordered randomly, but I want to make sure that every number is used once. Here's what I have, which loops endlessly trying to land on the last exact numbers...
Code:
    Dim i As Integer
    Dim j As Integer
    Dim randomNumber As Integer
    Randomize
    For i = 0 To 188
        numArr(i) = -1
    Next
    
    i = 0
    Do While i <= 188
        randomNumber = Round(188 * Rnd(1), 0)
       
         For j = 1 To UBound(numArr)
             If randomNumber = numArr(j) Then
                 Exit For
             ElseIf numArr(j) = -1 Then
                 numArr(j) = randomNumber
                 i = i + 1
                 Exit For
             End If
         Next
    Loop

Thanks for any help!
-- Just trying to help... LOL [ponder]
 
Try this thread222-321406 If you choose to battle wits with the witless be prepared to lose.
[machinegun][hammer]

[cheers]
 
Here are two solutions I developed:

1. Use a 2 dimensional array....
Code:
for i = 0 to ubound(myArr,1)
  myArr(i,0) = RND()
  myArr(i,1) = -1
next
for i = 0 to ubound(myArr,1)
  numHigher = 0
  thisVal = myArr(i,0)
  for j = 0 to ubound(myArr,1)
    if thisVal > myArr(j,0) then
      numHigher = numHigher + 1
    elseif thisVal = myArr(j,0) then
      myArr(j,0) = myArr(j,0) + .0000000000001
    end if
  next
  numArr(i,1) = numHigher
next

2. Use a one-dimensional array and reset the random number for the lowest random number to 1 - continue through whole array....
Code:
[code]
for i = 0 to ubound(myArr)
  myArr(i) = RND()
next
for i = 0 to ubound(myArr)
  lowestVal = myArr(0)
  lowestPos = 0
  for j = 0 to uBound(myArr)
    if myArr(j) < lowestVal then
      lowestVal = myArr(j)
      lowestPos = j
    end if
  next
  myArr(lowestPos) = i + 1
next
-- Just trying to help... LOL [ponder]
 
Since the array has only 188 elements why not try this ...


for i = 0 to 188
aNumArray(i) = i
next

randomize
for i = 0 to 188
vTemp=int(rnd*188)
vLast=aNumArray(vTemp)
aNumArray(i)=aNumArray(vTemp)
aNumArray(vTemp)=vLast
next

Hope, i helped ...


ARISTON Engineering Ltd
Michael Vezyrgianopoulos
R&D Manager
 
basically, because the request is for non repeating values.

MichaelRed
m.red@att.net

Searching for employment in all the wrong places
 
This program works, i made it a few weeks, ago. Talk about a brain twister. Post here again if you have questions about it.

' TxtInput Input box that user enters max number to count to, in your case 188
' CmcEnter Command button that sorts numbers
' CmdNext Command button that grabs unused number in range
' Lbloutput Where the output it sent to display at

Option Explicit
Dim runonce ' allow Sort Button to run only 1 time
Dim clicknum As Integer ' counter for display purposes
Dim ArrayHolder(100) As Integer ' array to hold final selected numbers


Private Sub CmcEnter_Click()
If runonce = False Then
Dim answer As Integer ' variable that holds the total group number
Dim randomHolder As Integer ' variable to hold each random selection
Dim nCount As Integer ' counter for number of selections made
Dim nCheck As Integer ' counter for check on previous selections
answer = TxtInput.Text
For nCount = 1 To answer
start: ' lets go (again)
Randomize ' random-seed the random generator
randomHolder = Int((answer * Rnd) + 1) ' pick random number from 1 to what the user entered
For nCheck = 1 To answer ' sets loop from 1 to entered number
If randomHolder = ArrayHolder(nCheck) Then ' if seleced number has already been picked...
GoTo start ' go back and pick another number.
End If
Next nCheck
ArrayHolder(nCount) = randomHolder ' store selection in array
Next nCount
runonce = True
End If

End Sub


Private Sub CmdNext_Rand_Num_Click()

Dim counter As Integer
clicknum = clicknum + 1 ' counter for display purposes
Lbloutput.Caption = ArrayHolder(clicknum) ' displays the stored value in the array
If (ArrayHolder(clicknum) = 0) Then
lbldone.Visible = True
Lbloutput.Visible = False
End If

End Sub

 
HI

Im stevecclfford you responded to my question about access, how can i send you the data?

THANKS!
 
Instead of checking to see if the number is used, try randomizing the ones that are left. This routine finishes after 2 * 188 loops :


Private Sub make_array()
Dim coll As New Collection
Dim New_array(1 To 188) As Integer
Dim i, r As Integer

For i = 1 To 188
'initialize 188 integers in a row
coll.Add i
Next i

For i = 1 To 188
'select, record and remove randomly
r = Int(coll.Count * Rnd + 1)
New_array(i) = coll.Item(r)
coll.Remove (r)
Next i

End Sub
 
I do thank everyone for the responses. As I noted above, I developed 2 solutions which work quite well and are efficient and easily coded.

merlinx, how does that ensure no duplicate values?

candyMan, it looks like your solution won't solve the initial problem of continually waiting while you are waiting to find that last random number (for instance let's say that all numbers except 137 have been selected - you are waiting for your random number generator to generate 137...) -- Just trying to help... LOL [ponder]
 
mwolf00,

part 1 creates a collection of 188 items ( numbers 1 to 188 )

part 2 randomly selects an item in the collection, then the selected item is removed.

if you look at the second step you will notice that the randomize reduces by one with each loop, (coll.count).

 
Nice! You get a star (but I'm still using my solution [wink]) -- Just trying to help... LOL [ponder]
 
merlinx,

an interesting (and apparently efficient) approach. I took the liberty of generalizing the procedure and -because I find many using VB not familiar with the use of arrays in general and passing them between procedues in particular, I added a small routine to illustrate how this (generalized version could actually be used in a broader scope.


The &quot;working&quot; Routine
Code:
Public Function basMkAry(MyAry() As Long) As Long()

    'Adapted my Michael Red, 11/15/02 from posting _
     Tek-Tips thread222-405021  by &quot;merlinx&quot;

    Dim MyColl As New Collection
    Dim Idx As Long
    Dim Jdx As Long

    ReDim MyAry(1 To UBound(MyAry))

    Idx = 1
    While Idx <= UBound(MyAry)
        MyColl.Add Idx
        Idx = Idx + 1
    Wend

    Idx = 1
    While Idx <= UBound(MyAry) 'select, record and remove randomly
        Jdx = Int(MyColl.Count * Rnd + 1)
        MyAry(Idx) = MyColl.Item(Jdx)
        MyColl.Remove (Jdx)
        Idx = Idx + 1
    Wend

End Function

The procedure to &quot;illustrate&quot; the use of the above
Code:
Public Function basTestRndAry(NumIn As Long)

    Dim Idx As Long
    Dim MyRnd() As Long

    ReDim MyRnd(NumIn)

    Call basMkAry(MyRnd)            ' = basMkAry(NumIn)

    Idx = 1
    While Idx <= NumIn
        Debug.Print MyRnd(Idx)
        Idx = Idx + 1
    Wend

End Function


MichaelRed
m.red@att.net

Searching for employment in all the wrong places
 
Nice! You get a star (but I'm still using my solution )


I also think merlinx deserves a star, and, the above reminds me of some old adage? &quot; ... pride goeth before ...&quot; ?

Even with the overhead of my generalization, merlinx's routine is ~~ 1/3 the code -which should translate to ~~ 1/3 the execution time. Surely this is a useful feature for all but the most trivial applications?

But perhaps I should recognize that this IS a trivial app, as the original post focuses on the single fixed size array?



MichaelRed
m.red@att.net

Searching for employment in all the wrong places
 
Michael,

Nice advancement. I personally like to work with pointers, which is a bit more advanced or instead of passing arrays I use a variant and put the array in the variant. Easier to use
example ;

sub make_array(byval Array_pointer as long)

function make_array()as Variant

some what more ;

function make_array(byval from_num as integer, byval to_num as integer)as variant

----------------------
there are many ways to get things done and I like your approach in breaking it down to smaller parts.
 
Point taken Michael. I guess since I have never worked w/ collections, I'm more comfortable w/ arrays. Of course, if I don't start working w/ collections, I won't ever be comfortable with them.

Someday I will have the knowledge that you and Merlinx posses today - at which point you will have more knowledge that you do today - so I guess I'll always have more to learn....
-- Just trying to help... LOL [ponder]
 
mwolf00,

Collections are relatively easy to master. first you need to dim your collection, but this alone will not work because your collection is an object which has to be created! So we dim it as a new object ;

dim my_col as new collection

Now it's ready to use. We can store other things in it, for example different types of variables with the add command ;

my_col.add ( this_string )
my_col.add ( this_integer )
my_col.add ( this_node )

and so on. Important is that you know ahead of time what you are going to extract. for variables you can identify them with the VarType function in VB. There are a number of things which are useful here. Also you can put it in a module globaly and not have to pass things back and forth, just use it.

retrieving items for example ;

my_variant = my_col.item(index)

remove things with ;

my_col.remove

How many things are in there?

my_integer = my_col.count

need more thought ;

my_new_col.add ( my_col ) ' add a collection to a collection.

Collections are very useful.

have fun, and good luck.
 
A note to such things, using things like option explicit, LBound, Ubound are very useful although I find using the for each easier and faster to programm.

for example a collection of integers ;

dim i as integer

for each i in my_col
' my_col can have in this case only int.
debug.print i
next i
 
Also to better visualize the collection, think about the tree view element. Last week I wanted a directory copy in a module so I used a collection and added nodes. worked well, no forms and no controls. Everything as required for what I was doing...
 
Thank you merlinx. If you can indulge a few more questions.

[ol][li]Can I use the FOR EACH construction with OPTION EXPLICIT (after I dim the variable I use to step through)?
[li]What is the difference between a collection and an array (besides the add and remove methods)?
[li]In your code( r = Int(coll.Count * Rnd + 1)), why do you use &quot;+1&quot;?
[li]Can you have a collection of arrays, images or other objects?
[li]Do collections have to contain one data type? Using separate collections for each data type?
[/ol] -- Just trying to help...
[wolf]<--- This is a wolf? We need a new icon.......
mikewolf@tst-us.com
 
Dictionarys make the code short and sweet.

Private Sub MakeRandomArray()
Dim RandArray(187) As Long
Dim RandomNumber As Long
Dim RandDict As Dictionary 'set Micrsoft Scripting Runtime reference
Set RandDict = New Dictionary
Dim i As Long
Do Until i = 187
RandomNumber = Round(188 * Rnd(1), 0)
If RandDict.Exists(RandomNumber) = False Then
RandDict.Add RandomNumber, 0
RandArray(i) = RandomNumber
Debug.Print RandArray(i)
i = i + 1
End If
Loop

End Sub
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top