0

I want to generate a random string of length 9.

This is the code which hits collision about 10-15 times. Credits to Random String Generator Returning Same String. Can anybody help me to generate a truly random string?

  class Program
    {

        private static Random random = new Random((int)DateTime.Now.Ticks);
        private static object locker = new object();

        private static string RandomString(int size)
        {
            StringBuilder builder = new StringBuilder();
            char ch;
            for (int i = 0; i < size; i++)
            {
                lock (locker)
                {
                    ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
                }
                builder.Append(ch);
            }

            return builder.ToString();
        }



        static void Main(string[] args)
        {            
            Dictionary<string, string> dict = new Dictionary<string, string>();
            object locker2 = new object();

            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) => {
                for (int i = 0; i < 5000000; i++)
                {
                    string random = RandomString(9);
                    lock (locker2)
                    {
                        if (!dict.ContainsKey(random))
                            dict[random] = random;
                        else
                            Console.WriteLine("Found");
                    }

                }
            }));

            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
            {
                for (int i = 0; i < 5000000; i++)
                {
                    string random = RandomString(9);
                    lock (locker2)
                    {
                        if (!dict.ContainsKey(random))
                            dict[random] = random;
                        else
                            Console.WriteLine("Found");
                    }

                }
            }));

            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
            {
                for (int i = 0; i < 5000000; i++)
                {
                    string random = RandomString(9);
                    lock (locker2)
                    {
                        if (!dict.ContainsKey(random))
                            dict[random] = random;
                        else
                            Console.WriteLine("Found");
                    }

                }
            }));

            ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
            {
                for (int i = 0; i < 5000000; i++)
                {
                    string random = RandomString(9);
                    lock (locker2)
                    {
                        if (!dict.ContainsKey(random))
                            dict[random] = random;
                        else
                            Console.WriteLine("Found");
                    }

                }
            }));

            Console.ReadKey();
        }
    }
Community
  • 1
  • 1
Jack
  • 7,433
  • 22
  • 63
  • 107
  • What is your definition of "string"? What characters are allowed? – Sergei Rogovtcev Aug 16 '12 at 08:48
  • @Serg: A to Z and possibly even 0-9 will do. But I don't want other characters. No = etc. – Jack Aug 16 '12 at 08:49
  • How about re-generating a new string if there is a collision? – Filip Ekberg Aug 16 '12 at 08:56
  • @Filip: That's fine but that comes with it's own overhead. I would have to then store it in database and check against it every time :(. – Jack Aug 16 '12 at 09:06
  • @Jack, Do you want to be safe against collisions even if you run the applicaiton on different times? Otherwise, why not just store a list in memory (if it's not too many records at the same time). – Filip Ekberg Aug 16 '12 at 09:08
  • @Filip: I want it to safe all the times. This is a web application. If Asp.Net application pool etc cycles, that would mean all items stored in memory are lost. – Jack Aug 16 '12 at 09:09
  • @Jack, Yes. But I'm guessing you store it in a database anyways? Just index the column. Will be a little over-head but not that much if collision is an issue – Filip Ekberg Aug 16 '12 at 09:10

3 Answers3

1

Even using a perfectly random string without constraints, you'll likely get collisions once you generate around 2 million entries. There are 26^9 total strings. Collisions become likely once you hit around the square root of that, which is around 2.3 million. Check out the Birthday problem.

You have a couple of choices:

  • Increase the number of possible strings significantly. This means a longer string, and possibly more characters
  • Keep track of existing values, and reject them.
  • Use a counter and pass it to a pseudo random permutation of the desired size.
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
0

It might perform as well, but if you need a truly random number you should use the RandomNumberGenerator class. This gives you a crypto-random number and will do a better job distributing the random-ness. This, of course, only really matters if you need crypto-random strings. This SO question does a good job at discussing the difference.

Community
  • 1
  • 1
Davin Tryon
  • 66,517
  • 15
  • 143
  • 132
0

Use a GUID and condense that to a string of your liking.

primfaktor
  • 2,831
  • 25
  • 34
  • Guid is random but it's part is not. I want a random string of length 9. Not more not less. Guid can't guarantee that to be random. – Jack Aug 16 '12 at 09:25
  • That's what I meant with “condense”, i.e. boil it down so that the the uniqueness remains. But of course that is impossible, you'll have a collision latest after `36^9` tries. Also, without giving an actual algorithm it's not of much help. Just wanted to give a quick hint. – primfaktor Aug 16 '12 at 09:41