Yorrick
Yorrick

Reputation: 377

Make array containing characters randomly taken from 3 different char arrays

I'm having a problem with making an array containing 8 different characters, each of which is taken from one of 3 different char arrays (one containing strictly lowercase characters, the second only containing uppercase characters and the third containing only numbers).

The problem is, it's supposed to take 1 character at a time from a random char array.

My arrays containing each set of characters is declared here:

Dim lcase() As Char = "abcdefghijklmnopqrstuvwxyz".ToCharArray()
Dim ucase() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
Dim num() As Char = "0123456789".ToCharArray()
Dim chars(7) As Char

As for the code to fill up the final array (in my case, chars(7)):

Dim lim As Short = rand.Next(1, 5)
For x = 0 To lim
    Dim char_num As Integer = rand.Next(0, lcase.GetUpperBound(0))
    chars(x) = lcase(char_num)
Next
Dim lim2 As Short = 6 - lim
For x = 0 To lim2
    Dim char_num As Integer = rand.Next(0, num.GetUpperBound(0))
    chars(x) = num(char_num)
Next
For x = 0 To 6 - lim2
    Dim char_num As Integer = rand.Next(0, ucase.GetUpperBound(0))
    chars(x) = ucase(char_num)
Next

This works, although for some reason it tends to (for some reason) leave certain values null, ending up in me getting outputs like these:

QHK M  D
 LCR86  

What I need is for my code to fill up the array properly, so it contains proper values, each taken from the three char arrays.

Note: my chars(7) is declared as Char because I swap around the characters contained in it after they were generated, to create a completely random string out of those characters.

I suspect I made a mistake somewhere in the code which fills up the array, but in case my mistake isn't in the code above, here's the code which randomizes the order of the characters in my chars() array:

Dim j As Integer
Dim swap As Char
Dim r As Random = New Random()

For i As Integer = 0 To chars.GetUpperBound(0)
    j = r.Next(0, i)
    swap = chars(j)
    chars(j) = chars(i)
    chars(i) = swap
Next i

Thanks in advance guys.

Update: I realized my mistake, the for loops keep overwriting what has already been added to the array, thus leaving the last few spots open. All I need now is a way to have them properly add them to the first empty slot.

Upvotes: 0

Views: 670

Answers (3)

Joel Coehoorn
Joel Coehoorn

Reputation: 416059

Why 3 separate arrays? Why not one big one that comprises your "alphabet", like this:

Dim alphabet() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray()

I can hear you now saying, "But how do I know it picks from each of the character sets?". Part of the answer is that it's not truly random unless the chance exists to pick from an array zero times. The other part is that, if you really need to, you can always just validate an output and re-roll.

That gives you much simpler code:

Dim alphabet() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789".ToCharArray()
For x As Integer to chars.Length - 1
   chars(x) = rand.Next(0, alphabet.Length)
Next
Return New String(chars)

That's it. That's the whole thing. There's also no need to shuffle these results.

Another nice feature is that this it makes it easy to tweak your alphabet. For example, when communicating these codes to end users, it's often useful to drop certain characters from the alphabet to avoid confusion. To do this, now you only need to change one string:

Dim alphabet() As Char = "ABCDEFGHIJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz123456789".ToCharArray()

If you look at this carefully, you'll notice that three characters are missing: uppercase 'O', lower-case 'L', and numeral '0'. By leaving out these characters and making sure to choose a font that properly distinguishes the others (Courier New will work, but most variable-width fonts will need to drop more characters), you can avoid a good number of calls to your help desk.

Upvotes: 0

Yorrick
Yorrick

Reputation: 377

Ended up finding the solution myself, my initial code kept overwriting the first values instead of continuing the array where the previous loop left off.

Here's the code which actually works:

Dim lcase() As Char = "abcdefghijklmnopqrstuvwxyz".ToCharArray()
Dim ucase() As Char = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray()
Dim num() As Char = "0123456789".ToCharArray()
Dim chars(7) As Char

Dim lim As Short = rand.Next(1, 6)

For x = 0 To 7
    Dim char_num As Integer = rand.Next(0, lcase.GetUpperBound(0))
    chars(x) = lcase(char_num)
Next

For x = 0 To lim
    Dim char_num As Integer = rand.Next(0, num.GetUpperBound(0))
    chars(x) = num(char_num)
Next

lim = rand.Next(1, 5)

For x = 0 To lim
    Dim char_num As Integer = rand.Next(0, ucase.GetUpperBound(0))
    chars(x) = ucase(char_num)
Next

Upvotes: 0

tinstaafl
tinstaafl

Reputation: 6948

I think you may be over thinking things a bit. a simple function that finds the characters directly using ASCII codes would probably be much simpler and easier to debug. Something like this:

Private Function GenPass() As Char()
    Dim OutVal(7) As Char
    Dim nextchar As Char
    Dim rand As New Random(Now.Millisecond)
    For I = 0 To 7
        Do
            nextchar = Chr(rand.Next(48, 122))

        Loop Until Not OutVal.Contains(nextchar) AndAlso Not (nextchar > "9"c AndAlso nextchar < "A"c) AndAlso Not (nextchar > "Z"c AndAlso nextchar < "a"c)
        OutVal(I) = nextchar
    Next
    Return OutVal
End Function

The output is an array of Char with random alphanumeric values. Here's one such output:

?GenPass
{Length=8}
    (0): "L"c
    (1): "l"c
    (2): "W"c
    (3): "8"c
    (4): "P"c
    (5): "E"c
    (6): "c"c
    (7): "2"c

Upvotes: 1

Related Questions