5

I need to create a random string which should be between the length of 6 to 10 but it sometimes generates only about the length of 3 to 5. Here's my code. Can anyone would be able to find out the problem? :(

            int lengthOfName = (int)(Math.random() * 4) + 6;
        String name = "";
        /* randomly choosing a name*/
        for (int j = 0; j <= lengthOfName; j++) {
            int freq = (int)(Math.random() * 100) + 1;
            if(freq <= 6){
                name += "a";
            }if(freq == 7 && freq == 8){
                name += "b";
            }if(freq >= 9 && freq <= 11){
                name += "c";
            }if(freq >= 12 && freq <= 15){
                name += "d";
            }if(freq >= 16 && freq <= 25){
                name += "e";                        
            }if(freq == 26 && freq == 27){
                name += "f";
            }if(freq == 28 && freq == 29){
                name += "g";
            }if(freq >= 30 && freq <= 33){
                name += "h";
            }if(freq >= 34 && freq <= 48){
                name += "i";
            }if(freq == 49 && freq == 50){
                name += "j";
            }if(freq >= 51 && freq <= 55){
                name += "k";
            }if(freq >= 56 && freq <= 60){
                name += "l";
            }if(freq == 61 && freq == 62){
                name += "m";
            }if(freq >= 63 && freq <= 70){
                name += "n";
            }if(freq >= 71 && freq <= 75){
                name += "o";
            }if(freq == 76 && freq == 77){
                name += "p";
            }if(freq == 78){
                name += "q";
            }if(freq >= 79 && freq <= 84){
                name += "r";
            }if(freq == 85 && freq == 86){
                name += "s";
            }if(freq == 87 && freq == 88){
                name += "t";
            }if(freq >= 89 && freq <= 93){
                name += "u";
            }if(freq == 94){
                name += "v";
            }if(freq == 95 && freq == 96){
                name += "w";
            }if(freq == 97){
                name += "x";
            }if(freq == 98 && freq == 99){
                name += "y";
            }if(freq == 100){
                name += "z";
            }
        }
Max
  • 273
  • 1
  • 6
  • 15
  • 4
    Can we propose a better solution instead of these nested and impossible conditions? – bakkal Jun 05 '10 at 02:00
  • This *begs* to be rewritten using a switch statement or, perhaps better, an array lookup. (Though that is beside the point of the question) – David Z Jun 05 '10 at 02:17

8 Answers8

20

I'm sorry but the code is too poorly written to be salvageable. I recommend something like this.

    Random r = new Random(); // just create one and keep it around
    String alphabet = "abcdefghijklmnopqrstuvwxyz";

    final int N = 10;
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < N; i++) {
        sb.append(alphabet.charAt(r.nextInt(alphabet.length())));
    }
    String randomName = sb.toString();

    System.out.println(randomName);

Key points are:

  • Use java.util.Random, specifically nextInt(int n) to get a random int in a given range
    • No need for funky formulas
  • When building a string in a loop, use StringBuilder.
  • Use an alphabet string, and charAt to index its letters.

API links

Related questions


Problems with the original code

There are plenty, unfortunately.

  • String += in a loop yields very poor performance for longer strings
  • for (int j = 0; j <= lengthOfName; j++) is an off-by-one-error
  • freq == 7 && freq == 8 is a logical contradiction
  • It's just unnecessarily verbose!
    • Warning signs should go off whenever you write something like that

I highly recommend doing lots of small but simple exercises to learn Java basics. codingbat.com is great; it has hundreds of these, they're automatically graded so you'll know when your solution works as expected or not. It has sections on logic, strings, arrays, etc.


On uneven letter distribution

The simplest solution is to just have duplicates in the alphabet:

  • String alphabet = "aab"; will have probability for a twice as much as b
  • You can generate the alphabet programmatically from a frequency table
    • I'll leave this as an exercise (or you can ask another question if you need it)
Community
  • 1
  • 1
polygenelubricants
  • 376,812
  • 128
  • 561
  • 623
  • Thanks for your code!! but the alphabet is not supposed to be distributed in the same proportion so couldn't think of any better way.... for e.g the alphabet "a" has to be distributed in 6% of chance – Max Jun 05 '10 at 02:17
  • 2
    @Max, then use a string like "aaaaaabbccc...." (instead of "abcde...") which is of length 100, and use the code above. polygeneL used the word 'like', so I suppose he expected you to do some work :-) –  Jun 05 '10 at 02:20
  • @Moron, True that. Yeap I'm working on it already!! Thanks for your comment! – Max Jun 05 '10 at 02:24
  • 2
    Maybe http://stackoverflow.com/questions/2971315/string-stringbuffer-and-stringbuilder/ (Java) is more appropriate? Since 73883 is C# .NET, I agree it is pretty much the same concepts. – bakkal Jun 05 '10 at 02:30
  • 2
    Nice answer polygenelubricants! And Moron is no moron. – President James K. Polk Jun 05 '10 at 02:32
5

Conditions like if(freq == X && freq == X+1) are always false.

You probably meant to use || (OR)

Soufiane Hassou
  • 17,257
  • 2
  • 39
  • 75
5

Your code has a lot of repetitions of the same problem:

if(freq == 28 && freq == 29) { ... }

You are telling Java to follow a condition when freq equals to 28 AND freq equals to 29. It's impossible. You will want to use the OR operator:

if(freq == 28 || freq == 29) { ... }

What's happening now is that when freq equals to any number inside those mistaken conditions, nothing will be added to your string and it will become smaller.

Paulo Guedes
  • 7,189
  • 5
  • 40
  • 60
3

Here is my solution:

import java.util.Random;

Random gen = new Random(474587); //put in random seed
int min = 6;
int max = 10;

// we want 20 random strings 
for(int i=0; i < 20; i++){
 int len = min+gen.nextInt(max-min+1);
 StringBuilder s = new StringBuilder(len);
 while(s.length() < len){
  //97 is ASCII for character 'a', and 26 is number of alphabets
  s.append((char)(97+gen.nextInt(26)));     
 }

System.out.println(s.toString());
}

Sample of output:

zqwloh
jefcso
spcnhxyyk
tzlobaukn
keyxkn
cllhsxybz
ieaudei
bolfzqlxrl
scpfcbztyh
thkfrybffe
nbspabxjh
bakkal
  • 54,350
  • 12
  • 131
  • 107
2

You seem to have made some typos. On one occasion you write

if(freq == 49 && freq == 50){ name += "j";

which is in fact never true.

Jeff
  • 21
  • 1
1

I bet that you no longer need an answer, but since I've never answered a stack overflow question before, I though this would be a good warm-up problem.

One thing that everyone else seemed to leave out is the frequency aspect of your code. The following code will create 10 random words of length 6 to 10 according to the frequency you wanted:

import java.util.Random;


public class Stuff {
public static void main(String[] args) {

    Random rand = new Random();
    int[] freqs = new int[] {6,8,11,15,25,27,29,33,48,50,55,60,62,70,75,77,78,84,86,88,93,94,96,97,99,100};

    int numWords = 10;
    for(int i = 0; i<numWords; i++)
    {
        String word = "";
        int numLetters = 6 + rand.nextInt(5);
        for(int j = 0; j<numLetters; j++)
        {
            int freq = rand.nextInt(100) + 1;
            int index = 0;
            while(freqs[index] < freq) index++;
            word = word + (char)(97 + index );              
        }
        System.out.println(word);
    }
}

Now, my question for you is can you tell me how this works?

JB

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
JnBrymn
  • 24,245
  • 28
  • 105
  • 147
0

That's what I came up with

import java.util.*;
public class RandomString6to10

{
    public static void main(String[] args)
    {
        Random rnd = new Random();
        Scanner scan = new Scanner (System.in);
        String alphabets = "abcdefghijklmnopqrstuvwxyz";
        int min1 = rnd.nextInt(5) + 6;
        int min2 = rnd.nextInt(3) + 3;
        System.out.println("How many strings do you want?");
        int x = scan.nextInt();

        for ( int i = 0; i < x; i++)
        {
/* because you didn't tell us when should the generator decide to choose 6-10 or 3-5 
so I made it random */

            if (rnd.nextBoolean()) 
            { 
                min1 = rnd.nextInt(5) + 6;
                for (int t=0; t < min1; t++)
                {
                    int randomString1 = rnd.nextInt(alphabets.length());
                    System.out.print(alphabets.charAt(randomString1));
                }
                System.out.println();
            }
            else 
            {
                min2 = rnd.nextInt(3) + 3;
                for (int j=0; j < min2; j++)
                {
                    int randomString2 = rnd.nextInt(alphabets.length());
                    System.out.print(alphabets.charAt(randomString2));
                }
                System.out.println();

            }
        }
    }
}
0x2bad
  • 308
  • 2
  • 11
0

Just for reference and completeness, here's an "easy" (but less efficient) solution assuming that presence of numbers in the string isn't a big issue:

private static final Random random = new Random();

public static String generateRandomString() {
    return new BigInteger((4 + random.nextInt(3)) * 8, random).toString(36);
}

This generates a random string matching [a-z0-9] of length 6~10 (inclusive).

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555