- ベストアンサー
比重をつけて連想配列の中からランダムに選び出す方法
PHP Version 5.1.6を使っています。 例えば $arr = array( 'key1' => array('name' => 'あ', 'weight' => 1), 'key2' => array('name' => 'い', 'weight' => 1), 'key3' => array('name' => 'う', 'weight' => 3), ); という連想配列があった時に、 weightの値によってランダムに選ばれる時の差をつけたいのですが、 具体的には、1が最も選ばれ易くて値が大きくなるにつれて選ばれ難くなるようにしたいです。 上の場合だと、key1とkey2が選ばれ易くてkey3は選ばれ難くなります。 逆(1が最も選ばれ難くて、値が大きくなるに連れて選ばれ易い)の場合は なんとかプログラムで表すことができたのですが、 この場合はどのような感じになるのでしょうか?
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
そんなときこそ颯爽とソースを晒してcoolに逃げるに限ります。 [改定前] $arr = array( "k1"=>array("value"=>"a","seed"=>1) ,"k2"=>array("value"=>"b","seed"=>2) ,"k3"=>array("value"=>"c","seed"=>3) ); $arr_child = array(); $keys = array(); foreach($arr as $key => $values) { $arr_child[] = $values["seed"]; $keys[] = $key; } $sum=0; foreach($arr_child as $kk => $vv) $sum = $sum + $vv; $r = mt_rand(0,$sum); $ii = 0; $seed = 0; $p = 0; while($r > $seed) { $p = $ii; $seed = $seed + $arr_child[$ii]; $ii++; } echo $arr[$keys[$p]]["value"]; [改定後] $arr = array( "k1"=>array("value"=>"a","seed"=>1) ,"k2"=>array("value"=>"b","seed"=>2) ,"k3"=>array("value"=>"c","seed"=>3) ); $arr_child = array(); $keys = array(); foreach($arr as $key => $values) { $arr_child_tmp[] = $values["seed"]; $keys[] = $key; } $sum_tmp=0; foreach($arr_child_tmp as $kk => $vv) $sum_tmp = $sum_tmp + $vv; foreach($arr_child_tmp as $num => $seed_tmp) { if($seed_tmp != 0) $arr_child[] = $sum_tmp / $seed_tmp; else $arr_child[] = 0; } $sum = 0; foreach($arr_child as $kk => $vv) $sum = $sum + $vv; $r = mt_rand(0,$sum); $ii = 0; $seed = 0; $p = 0; while($r > $seed) { $p = $ii; $seed = $seed + $arr_child[$ii]; $ii++; } echo $arr[$keys[$p]]["value"]; つまるところ、逆数の比にしてランダムすれば良いです。 // 仕事しろ俺
その他の回答 (2)
- yambejp
- ベストアンサー率51% (3827/7415)
選ばれやすいというのは1は3の3倍選ばれやすいということでしょうか? 逆ができたなら1/weightみたいなことで調整できるのでは? その逆というソースを例示してみてはどうでしょうか?
お礼
ご返答ありがとうございます。 yambejpさんにもANo.1のお礼のサンプルを参考にして(全く違うやり方でも) 考えてもらえないでしょうか?
- gogo724275
- ベストアンサー率16% (1/6)
>なんとかプログラムで表すことができたのですが、 そのソースを示した方が回答しやすいと思います。
お礼
ご返答ありがとうございます。 すいません、汚いプログラムだったので自分的にはあまり表示したくなかったのですが、 これが逆(1が最も選ばれ難くて、値が大きくなるほど選ばれ易い)のプログラムです。 function random_choice($arr, $weight_key) { $cnt = 0; $wk = array(); foreach ($arr as $key => $val){ if($cnt >= 1){ $wk['start'][$cnt] = $wk['end'][$cnt-1] + 1; }else{ $wk['start'][$cnt] = 1; } $wk['end'][$cnt] = $wk['start'][$cnt] - 1 + $val[$weight_key]; $wk['key'][$cnt] = $key; $cnt++; } // print_r($wk); $max = count($arr); $rr = rand($wk['start'][0], $wk['end'][$max-1]); for ($j = 0; $j < $max; $j++){ if($wk['start'][$j] <= $rr && $rr <= $wk['end'][$j]){ $key = $wk['key'][$j]; break; } } return $key; } $arr = array( 'key1' => array('name' => 'あ', 'weight' => 1), 'key2' => array('name' => 'い', 'weight' => 1), 'key3' => array('name' => 'う', 'weight' => 3), ); $key = random_choice($arr, 'weight'); print "$key<br>\n"; これを(おそらく別のやり方かもしれませんが)どう改造すれば 1が最も選ばれ易くて、値が大きくなるほど選ばれ難くすることができるのでしょうか?
お礼
ご返答ありがとうございます。 試してみましたができました。ありがとうございます。