dポイントプレゼントキャンペーン実施中!

比重(比率)を利用して乱数を取得したいと思って、
そのような関数を探してたのですが見つからなかったので自作したのですが、
関数名の付け方に迷いがあるのでアドバイス頂けないでしょうか?

例えば
array(
 array('weight' => 3, 'min' => -3, 'max' => -1),
 array('weight' => 7, 'min' => 4, 'max' => 5),
)
と値を渡せば、
30%の確率で-3から-1の間でランダムした結果を取得
70%の確率で4から5の間でランダムした結果を取得
できます。

比重(weight)を利用してるので
「randByWeight」
と仮に名前を付けたのですが、
自分としてはそもそも文法的に合ってるのかも曖昧ですし、
プログラム的な命名規則に則してるかも分かりません・・・
まあそんなに深く考えずに「myrand」とかでもいいんでしょうけど、
この関数の作り方や設計の誤りなども含めてアドバイスして頂きたいです。

/**
 * randByWeight
 * 
 * @param $params
 * @return int
 */
function randByWeight($params)
{
 if (!isset($params[0])) {
  $params = array($params);
 }
 
 $index = 0;
 $range = array();
 foreach ($params as $param) {
  if ($index >= 1){
   $range[$index]['start'] = $range[$index - 1]['end'] + 1;
  } else {
   $range[$index]['start'] = 1;
  }
  $range[$index]['end'] = $range[$index]['start'] - 1 + (isset($param['weight']) ? $param['weight'] : 1);
  $index++;
 }
 
// srand( (int)( ((float)microtime()) * 1000000 ) );
 $ran = rand(1, $range[$index - 1]['end']);
 for ($i = 0; $i < $index; $i++) {
  if ($range[$i]['start'] <= $ran && $ran <= $range[$i]['end']) {
   if (isset($params[$i]['recursive']) && is_array($params[$i]['recursive'])) {
    return randByWeight($params[$i]['recursive']);
   } else {
    if($params[$i]['min'] > $params[$i]['max']) {
     $params[$i]['min'] = $params[$i]['max'];
    }  
    return rand($params[$i]['min'], $params[$i]['max']);
   }
  }
 }
}

// 使用例
$arr = array(
 array('weight' => 3, 'min' => -10, 'max' => 1),
 array(
  'weight' => 1,
  'recursive' => array(
   array('weight' => 1, 'min' => 2, 'max' => 2),
   array(
    'weight' => 10,
    'recursive' => array(
     array('weight' => 3, 'min' => 3, 'max' => 3),
     array('weight' => 7, 'min' => 4, 'max' => 4),
    ),
   ),
  ),
 ),
);
$result = array();
for ($i = 1; $i <= 100; $i++) {
 $result[randByWeight($arr)]++;
}
$sum = 0;
ksort($result);
foreach ($result as $value => $cnt) {
 print "{$value}:{$cnt}<br>\n";
 $sum += $cnt;
}
print "sum={$sum}<br>\n";

A 回答 (4件)

#1ですが


引数が全然違ったみたいで失礼しました。
書いてみましたがほとんど同じになってしまいましたw
一応速くはなった気がしますが合ってるかは不明。
少しでも参考になればいいですけど。

class WeightRandomizer {
 public static function execute($params) {
  if (!isset($params[0])) {
   $params = array($params);
  }
  
  $weightAll = 0;
  foreach($params as $param) {
   $weightAll += isset($param['weight']) ? $param['weight'] : 1;
  }
  $index = rand(1, $weightAll);
  
  $ws = 1;
  $we = 1;
  foreach($params as $param) {
   $we += isset($param['weight']) ? $param['weight'] : 1;
   if ($ws <= $index && $index <= $we) {
    if (isset($param['recursive']) && is_array($param['recursive'])) {
     return self::execute($param['recursive']);
    }
    if($param['min'] > $param['max']) {
     $param['min'] = $param['max'];
    }
    return rand($param['min'], $param['max']);
   }
   $ws = $we;
  }
 }
}

$rand = WeightRandomizer::execute($arr);
    • good
    • 0
この回答へのお礼

ご返答ありがとうございます。
いやでもたしかにこの設計の方が良さそうですね。
なるほど、自分としては
クラスで利用するとインスタンス化する手間が気がかりだったので
考えていなかったのですが、こうやって静的に使えばいいわけですよね。
勘違いしてました・・・

命名の方ですが、
たしかにByWeightなら慣例だと引数はweightですよね・・・
「WeightRandomizer」はいいですね。しっくりきます。
ところで「WeightRandomizer」の「izer(何とかザー)」という語尾は
主にクラスの命名に使うというイメージが自分にはあるのですが、
その認識は間違っているのでしょうか?
それとも一般の関数の命名に適用しても変ではないですか?

お礼日時:2009/01/07 16:43

一般的にクラス名は名詞、メソッドは動詞を使います。


という慣習からすると Random も一応名詞なので
Random::get() とかでも問題はなさそうです。

-ize で名詞や形容詞を「~化させる・する」の意味の動詞になるので
ランダム化させる+させる人(物)= Randomizer(乱数生成器)
英語は弱い子なので詳しくはお近くのお詳しい方にお願いします。

あえて izer をつけたのはかっこいいからです(キリッ
やっぱりかっこよくコーディングしたいです。
    • good
    • 0
この回答へのお礼

ご返答ありがとうございます。
なるほど、そのような区分けがあれば
名前の付け方も幾分楽になりそうですね。
「izer」はパターンとして使えそうです。

お礼日時:2009/01/07 21:14

読み返したら間違いが。


- $we = 1;
+ $we = 0;
    • good
    • 0

関数の中は見てないですが、命名は問題ないかと。


findById(integer) でIDを条件にレコードを取得だったりしますし。
ByWeightなら 引数はweightとかなと思ったりもしますが。
randByWeight($weight, $min = 0, $max = 1) //PHP的にはこっちかな
randByWeight($weight, $params = array())
クラス化すればまた変わるとは思います。
$rand = new RandomClass();
$rand->setWeight($weight);
print $rand->execute();
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!