just normal random? that's 1999? what time it is now?
Weighted Random allows one thing have more chance to pop up than the other! and you define the weight(chance)!
When I first met PHP, I tried to make a lot of scripts, weighted random is one of them. I soon forgot about it after I build it. Now, after a long time of reading other people's code, I think I can improve my first version a lot.
My first version
function rand_string_pro($array){
foreach($array as $var){
$i = 0;
while($i < $var['w']){
$string[] = $var['s'];
$i++;
}
}
return $string[array_rand($string)];
}
The input is a array like this(where $i can be any interger)
$array[$i]['s'] = 'string';
$array[$i]['w'] = 30;//only interger
I thought that code is perfect, until weeks ago I saw the flaws and start writing improvements. The list of flaws:
*huge weight can slow the script down, even produce memory overflow
*huge string with reasonable amount of weight can produce memory overflow too
*it does not seems FAST...
This list does not include error handling, because I don't think I need to program something to notice kind experienced programmers. Yes Yes, I know it is a bad act.
I did some improvement and released my 1.0 version
/*
Weighted Random Ver 1.0 by Mgccl(mgcclx@gmail.com)
Usage: input an numbered array
$array[$i][?s?] is the string you want to return
$array[$i][?w'] is the weight of the string
you can allow the function to find the GCD
sometimes it speeds up the script
To use GCD, use the function like
rand_string_pro($array, true);
Note: You need the math functions I wrote in
order to use GCD, you can find them here:
/2006/11/21/some-math-functions/
*/
function rand_string_pro($seed, $gcd = false){
$count = count($seed);
if($gcd == true){
foreach($seed as $var){
$gcd_array[] = $var[?w?];
}
$gcd = math_gcd_array($gcd_array);
if($gcd != 1){
$i = 0;
while($i < $count){
$seed[$i][?w?] /= $gcd;
++$i;
}
}
unset($gcd, $gcd_array);
}
$i = 0;
while($i < $count){
$n = 0;
while($n < $seed[$i][?w?]){
$key[] = $i;
++$n;
}
++$i;
}
return $seed[$key[mt_rand(0, count($key)-1)]][?s?];
}
The new version have these improvements:
* Weight divided by the GCD so we have smaller weights
* Produce a new array to store the key, and the key refer to the "key name" of the variable seed. No more huge array in the size of value
* Used ++$i instead of $i++, small speed up
But there is still a flaw in the system. It still creates a huge array if the GCD is small compare to the weight. The performance could still be slow.
I released the version 1.1, more like a usability improvement version
/*
Weighted Random Ver 1.1 by Mgccl(mgcclx@gmail.com)
Update: Nov/25/06 allow non-weighted random, separate the
string storing array and the weight storing array
Usage: input $array[$i] = 'string' format(where $i is a number)
$array[$i]is the string you want to return
$weight[$i]is the weight of the string
if one of the $array[$i] does not have a
$weight[$i] as a match, it automatically
set $weight[$i] as 1
To allow use weighted function, call the function like this
rand_string_pro($array, $weight);
you can allow the function to find the GCD
sometimes it speeds up the script
To use GCD, use the function like
rand_string_pro($array, $weight, true);
Note: You need the math functions I wrote in
order to use GCD, you can find them here:
/2006/11/21/some-math-functions/
*/
function rand_string_pro($seed, $weighted = false, $gcd = false){
$count = count($seed);
if($weighted === false){
return $seed[mt_rand(0, $count - 1)];
}else{
if($gcd === true){
if(count($weighted) != $count){
}else{
foreach($weighted as $var){
$gcd_array[] = $var;
}
$gcd = math_gcd_array($gcd_array);
if($gcd != 1){
$i = 0;
while($i < count($gcd_array)){
$weighted[$i] /= $gcd;
++$i;
}
}
unset($gcd, $gcd_array);
}
}
$i = 0;
while($i < $count){
if(empty($weighted[$i])){
$key[] = $i;
}else{
$n = 0;
while($n < $weighted[$i]){
$key[] = $i;
++$n;
}
}
++$i;
}
return $seed[$key[mt_rand(0, count($key)-1)]];
}
}
this version separated the input of the string array and the weight array
it also made the function usable when there is no weight present.
And finally, Version 1.2 is where I made the speed to the max.
/*
Weighted Random Ver 1.2 by Mgccl(mgcclx@gmail.com)
http://mgccl.com
Update: Nov/29/06
Faster Speed
allow non-weighted random, separate the
string storing array and the weight storing array
Usage: input $array[$i] = 'string' format(where $i is a number)
$array[$i]is the string you want to return
$weight[$i]is the weight of the string
if one of the $array[$i] does not have a
$weight[$i] as a match, it automatically
set $weight[$i] as 1
To allow use weighted function, call the function like this
rand_string_pro($array, $weight);
*/
function rand_string_pro($seed, $weighted = false){
$count = count($seed);
if($weighted === false){
return $seed[mt_rand(0, $count - 1)];
}else{
$i = 0; $n = 0;
$num = mt_rand(0, array_sum($weighted) + ($count-count($weighted)));
while($i < $count){
if(empty($weighted[$i])){
++$n;
}else{
$n += $weighted[$i];
}
if($n >= $num){
break;
}
++$i;
}
return $seed[$i];
}
}
Thi