tags:

views:

116

answers:

4

Hello,

I'd like to create a function which will generate a 3 char key string after each loop.

There are 26 chars in the alphabet and I'd like to generate totally unique 3 char keys (A-Z).

The output would be 17,576 unique 3 char keys (A-Z) - not case sensitive.

Can anyone give me an idea on how to create a more elegant function without randomly generating keys and checking for duplicate keys?

Is it possible

Thank you.

+9  A: 

If I read your question correctly you want to have a function that returns a key of the form "ABC" where each of the letters is selected randomly but the same combination of letters is never issued twice.

Do you mean never issued twice per execution of the code or never issued twice "ever"?

Either way I would look at generating all possible combinations, shuffling them and then storing them either in a member array or a file/database depending on your needs. You will also need to store an index which you simply increment each time you issue a key.

<?php
  private $keys = array();
  private $keyIndex = -1;

  function generateKeys()
  {
      $this->keys = array();
      $this->keyIndex = -1;

      for ($i=1; $i<=26; $i++)
      {
         for ($j=1; $j<=26; $j++)
         {
            for ($k=1; $k<=26; $k++)
            {
                $this->keys[] = sprintf('%c%c%c', 64+$i, 64+$j, 64+$k);
            }
         }
      }

      shuffle($this->keys);

      return $this->keys;
  }

  function getKey()
  {
      $this->keyIndex++;
      return $this->keys[$this->keyIndex];
  }

?>
Graphain
Thank you very much, works perfect.
cocacola09
+2  A: 

var use any math library to generate a random number from 0 to 26 cubed - 1, then assign the letters based on the value of that random integer...

in the following, the backslash represents integer division, i.e., drop any fractional remainder

first character = ascii(65 + integer modulus 26)
second character = ascii(65 + (integer \ 26) modulus 26
third character = ascii(65 + ((integer \ 26) \ 26) modulus 26

ahh, thx to @Graphain I realize you want to eliminate any chance of picking the same three character combination again... welll then here's a way...

  1. Create a collection (List?) containing 676 (26*26) 32 bit integers, all initialized to 2^26-1 (so bits 0-25 are all set = 1). Put 26 of these integers into each of 26 inner dictionaries so this becomes an dictionary of 26 dictionaries each of which has 26 of these integers. Label the inner dictionaries A-Z. Within each inner array, label the integers A-Z.
  2. Randomly pick one of 26 outer arrays (this sets the first character).
  3. From the array chosen randomly pick one of it's contained inner arrays. This sets the second character.
  4. Then randomly pick a number from 0 to n, (where n is the count of bits in the integer that are still set to 1)... Which bit in the number determines the last character.
  5. Set that bit to zero
  6. If all bits in the integer have been set to zero, remove integer from array
  7. If this inner array is now empty, (all integers are gone) remove it from outer array.
  8. Repeat from step 2 until outer array is empty or you get tired...

Here's some sample code (not tested):

 public class RandomAlphaTriplet
 {
    private static readonly Dictionary<char, Dictionary<char, int>> vals =
         new Dictionary<char, Dictionary<char, int>>();
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static readonly Random rnd = new Random(DateTime.Now.Millisecond);

    private const int initVal = 0x3FFFFFF;
    static RandomAlphaTriplet()
    {
        foreach (var c in chars)
            vals.Add(c, chars.ToDictionary(
                ic => ic, ic => initVal));
    }
    public static string FetchNext()
    {
        var c1 = chars[rnd.Next(vals.Count)];
        var inrDict = vals[c1];
        var c2 = chars[rnd.Next(inrDict.Count)];
        var intVal = inrDict[c2];
        var bitNo = rnd.Next(BitCount(intVal));
        var bitPos = 0;
        while (bitNo > 0)
        {
            if ((intVal & 0x0001) > 0) bitNo--;
            bitPos++;
            intVal <<= 1;
        }
        var c3 = chars[bitPos];
        inrDict[c2] &= ~(1 << bitPos);
        if (inrDict[c2] == 0) inrDict.Remove(c2);
        if (vals[c1].Count == 0) vals.Remove(c1);
        return string.Concat(c1, c2, c3);
    }
    private static int BitCount(int x)
    { return ((x == 0) ? 0 : ((x < 0) ? 1 : 0) + BitCount(x << 1)); }
} 
Charles Bretana
The OP wants the function to not return the same key twice.
Graphain
A: 

I can make it to only one key if you are interested. (I don't know if it is possible at all to have no key to check for duplication).

function getAlpha($Index) {
    $Alphabets = 'abcdefghijklmnopqrstuvwxyz';
    $Char      = substr($Alphabets, $Index, 1);
    return $Char;
}
function getRandom($Index) {
    $RandOne    =  $Index          % 26;
    $RandTwo    = ($Index / 26   ) % 26;
    $RandThree  = ($Index / 26*26) % 26;
    $AlphaOne   = getAlpha($RandOne);
    $AlphaTwo   = getAlpha($RandTwo);
    $AlphaThree = getAlpha($RandThree);
    $Rand = $AlphaOne.$AlphaTwo.$AlphaThree;
    return $Rand;
}
$Rands = array();
function getRandom() {
    global $Rands;
    while (true) {
        $RandNum = rand(0, 26*26*26 - 1);
        if (isset($Rands[$RandNum]))
            continue;
        $Rand            = getRandom($RandNum);
        $Rands[$RandNum] = $Rand;
        return $Rand;
    }
}

This only need one key to look up.

Hope this helps.

NawaMan
Does this stop the same key being returned twice?
Graphain
@Graphain: I've made some mistake but please look at my edited, it would looped until a unique random is found.
NawaMan
This has unpredictable run times and could potentially loop forever (unlikely, but possible). `while ( rand() )` is a bad pattern.
deceze
@deceze : you are right. This function is meant to be used when the function is not going to be call that many times. If it is needed to be call many times (like more than half of the possible values), you should use the function from Graphain.
NawaMan
A: 

Ehrm is this not “simple” combinatorial math? (Select all combinations of 3 out of 26? Or permutations of 3 out of 26?)