0

I have a program that creates a given number of folders named from a text file. I have the following algorithm:

private void button2_Click(object sender, EventArgs e)
{
    if (path != null && Directory.Exists(path))
    {
        Random rnd = new Random();
        for (int i = 0; i < value; i++)
        {
            var lines = File.ReadAllLines(path1);
            var randomLineNumber = rnd.Next(0, lines.Length);
            var line = lines[randomLineNumber];

            StringBuilder b = new StringBuilder();
            for (int j = 0; j < line.Length; j++)
            {
                char c = line[j];
                if (rnd.Next(2) == 0)
                {
                    c = Char.ToUpper(c);
                }
                b.Append(c);
                if (j % 2 == 1)
                {
                    b.Append(rnd.Next(10));
                }
            }
            line = b.ToString();

            Directory.CreateDirectory(Path.Combine(path, line));
        }
    }
}

I have a text file with one word on each line. My algorithm should take a random word from it and rename the folders that I create following the next rule:

lldlldll...ll and so on, where:
l - letter (upper case or lower case - it should be random) d - digit

Real example:
Number of folders: 13

My list:

computer
explore
wireless
dog
love
electrical
phone
alex
andrew
elevator
door

Desired output:

aN5dR0ew7
dO1G6
DO3oR5
CO4mP7uT6er8
pH6ON1e
al9EX5
eX0pl9Or4e
EL5eC0Tr8iC0aL7
lO4vE2
wi1re9le6Ss47
el3eV0AT8oR9

Actual output:

aN5dR0ew7
dO1G6
DO3oR5
DO4G7
DO6g1
Do9G1
eL4Ec6TR5Ic3Al9
EL5eC0Tr8iC0aL7
eX2Pl6OR7E8
wi1re9le6Ss47
Wi8Re7Le6ss54

The problem is the next one:

If I create 20 folders and I also have 20 words in that .txt file, the algorithm will not use all of the words but just some of them ( and it will repeat them 3 times). The digits are ok / the upper-lower letters are ok. I just have to be sure that each word from that txt will be used.

Any help please ?

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
Cajuu'
  • 1,154
  • 2
  • 19
  • 50

2 Answers2

5

There is no guarantee that a Random() instance will generate different values each time its Next method is called. 9 (nine) is a perfectly good random number, and it could be all you'll receive until the end of time.

What you want is the Fisher–Yates shuffle algorithm... You shuffle the lines of the txt file and so you guarantee that all the lines are used, and each line is only used once. If you need more lines than the file has, every time you have used all the lines of the file you re-shuffle it and restart.

This should be the full solution:

Random rnd = new Random();
var lines = File.ReadAllLines(path1);

for (int i = 0; i < value; i++)
{
    if (i % lines.Length == 0)
    {
        // We after using all the rows once
        // we used all of them (or at the beginning)

        // Shuffle, Fischer-Yates 
        int n = lines.Length;
        while (n > 1)
        {
            n--;
            int k = rnd.Next(n + 1);
            string value2 = lines[k];
            lines[k] = lines[n];
            lines[n] = value2;
        }
    }

    var line = lines[i % lines.Length];

    StringBuilder b = new StringBuilder();
    for (int j = 0; j < line.Length; j++)
    {
        char c = line[j];
        if (rnd.Next(2) == 0)
        {
            c = Char.ToUpper(c);
        }
        b.Append(c);
        if (j % 2 == 1)
        {
            b.Append(rnd.Next(10));
        }
    }
    line = b.ToString();

    Directory.CreateDirectory(Path.Combine(path, line));
} 
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • There is a guarantee: The `Random()` constructor sets it's seed determined by the system time. If one sets it explicitly, it'll be the same output every time. Although, there may be a seed for generating sequences of ⑨... – Binkan Salaryman Mar 09 '15 at 11:14
  • +1 for that link. Being a begginer in C# won't allow me to adapt that algorithm on my code, but I'll give it a shot. – Cajuu' Mar 09 '15 at 11:16
  • @BinkanSalaryman You are right, "a posteriori" (after the fact). Knowing a generated sequence you can regenerate it (with the seed), but without knowing the generated sequence, you can't know if it will be 9 9 9 9 9 9 9 or not :) – xanatos Mar 09 '15 at 11:16
  • 1
    @Alexander It isn't even clear exactly what you want to do... You have a txt file with 20 rows... A user sets value to 5... it generates 5 folders with random (different) names from the file. The user sets 21... What happens? It uses all the rows once and one of the rows twice? The user sets 41, all the rows twice and one row three times? – xanatos Mar 09 '15 at 11:17
  • @xanatos, it isn't a random name. Its pattern is described in the first post. More, if I `value`(number of folders) is 21 and there are only 5 words, each 4 words should be used 4 times and the 5th one should be used 5 times. – Cajuu' Mar 09 '15 at 11:22
0

I would create a list of integers right after this row

var lines = File.ReadAllLines(path1);
List<int> list = Enumerable.Range(0, lines.Length).ToList<int>();

Shuffle the list: Randomize a List<T>

and loop trought shuffled lines

for (int i = 0; i < list.Count; i++) {
      var lineItem = lines[i];
}
Community
  • 1
  • 1
eren
  • 708
  • 8
  • 20