I've created a small class to generate unique random strings. It works fine. I also want to log the collisions of the generated strings. I check if the generated string is in the array for uniquness:
public static function add(&$array = [], $length = 1) {
$hash = self::rand_str($length);
while (in_array($hash, $array, true)) {
$hash = self::rand_str($length);
}
$array[] = $hash;
}
To log the collisions, I need to modify the while
loop. I can push the hash
value into an array in the while
loop to log the collisions, but I want something more sophisticated.
public static function add(&$array = [], $length = 1) {
$hash = self::rand_str($length);
while (in_array($hash, $array, true)) {
self::$repeats[] = $hash;
$hash = self::rand_str($length);
}
$array[] = $hash;
return self::$repeats;
}
For example, it might generate a few non-unique strings in a row, then while
will run a few times. I want to log how many times while ran and what was the new string. The code above would output something like this:
$repeats = ["Usm", "rl2", "mJN", "XBU"];
This doesn't tell much. Have the collisions took place one right after another (in the same add()
)? What was the new unique random string that substituted the collision?
I want an output like this:
$repeats = [
// "while" ran count($repeats[i][0]) times
// repeats new value
[ ["Usm", "rl2", "mJN"], "XBU"], // add()
[ ["6cH" ], "GDd"], // add()
[ ["Kid", "Yjs" ], "no7"], // add()
];
I've created a method to log the collisions but it needs further work. I couldn't handle the forming of $repeats
array.
public static function log_repeat($hash, $new = false) {
if ($new) {
self::$repeats[count(self::$repeats)-1][] = $hash;
} else {
if (count(self::$repeats) == 0) {
self::$repeats[] = [[$hash]];
} else {
self::$repeats[count(self::$repeats)-1][0][] = $hash;
}
}
}
public static function add(&$array = [], $length = 1) {
$hash = self::rand_str($length);
$repeat_occured = false;
while (in_array($hash, $array, true)) {
$repeat_occured = true;
self::log_repeat($hash);
$hash = self::rand_str($length);
}
if ($repeat_occured) {
self::log_repeat($hash, true);
}
$array[] = $hash;
return self::$repeats;
}
This just pushes all the collisions into a single array, and unique strings are added next to each other:
$repeats = [
[ ["URF", "9IV", "2Z3", "STj", "z1T"], "v4Q", "f9S", "6T3", "6jy" ]
];
You can't tell which new string substituted which repeat. Each add()
should have its own row.
I know I need to modify add()
and log()
, but I'm stuck atm.
Full code:
class Hash {
public static $char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
public static $perm_limit = 0;
public static $repeats = [];
public static function rand_str($length = 1) {
$string = "";
for ($i = 0; $i < $length; $i++) {
$rand = rand(0, strlen(self::$char_set)-1);
$string .= self::$char_set[$rand];
}
return $string;
}
public static function log_repeat($hash, $new = false) {
if ($new) {
self::$repeats[count(self::$repeats)-1][] = $hash;
} else {
if (count(self::$repeats) == 0) {
self::$repeats[] = [[$hash]];
} else {
self::$repeats[count(self::$repeats)-1][0][] = $hash;
}
}
}
public static function add(&$array = [], $length = 1) {
$hash = self::rand_str($length);
$repeat_occured = false;
while (in_array($hash, $array, true)) {
$repeat_occured = true;
self::log_repeat($hash);
$hash = self::rand_str($length);
}
if ($repeat_occured) {
self::log_repeat($hash, true);
}
$array[] = $hash;
return self::$repeats;
}
public static function fill(&$array = [], $count = 1, $length = 1) {
self::$perm_limit = pow(strlen(self::$char_set), $length);
for ($i = 0; $i < $count; $i++) {
if (count($array) >= self::$perm_limit) {
break;
}
self::add($array, $length);
}
return self::$repeats;
}
}
Test case:
$hash_list = []
$repeats = Hash::fill($hash_list, 1000, 3);
var_dump($repeats);
var_dump($hash_list);
[1,2,3]
. I generate a new number, it's1
. It collides. I generate another one,2
. Collides again. I generate4
. Doesn't collide. Added to the array:[1,2,3,4]
. I generate5
. Doesn't collide. Added to the array:[1,2,3,4,5]
. Now,1
and2
were generated sequentially (right after each other, in the sameadd()
). So the output row would be[[1,2], 4]
.5
was added in anotheradd()
. \$\endgroup\$