2012-03-21 5 views
2

シャッフルのような配列をランダム化する関数が必要ですが、各要素のチャンスが違うという違いがあります。特別なシャッフル関数をPHPで行う方法

たとえば、次の配列を考慮してください。

$animals = array('elephant', 'dog', 'cat', 'mouse'); 

象は犬よりも最初のインデックスに乗るの高いチャンスがあります。犬は猫よりも高いチャンスを持っています。例えば、この特定の例では、象は1位に入る確率は40%、2位に入るのは30%、3位に入ると20%、最後には10%になる確率です。

シャッフルの後、元の配列の最初の要素は、最初の位置にある可能性が高くなりますが、最後の位置にある可能性が高くなります。

+2

興味深い質問ですが、各位置に終わる各要素の確率を割り当てるメカニズムは犯罪的に不十分です。 – Jon

+0

たとえば、10%未満ではどうなりますか? – Cyclone

+0

この場合、象は最後の位置にある確率は10%、最後の位置にない確率は90%です。 –

答えて

5

ノーマルshuffleはちょうど

  • が右
  • に左からそれらを拾って、いくつかの範囲でランダムにアイテムをドロップ

    • として実現することができます

      私たちはドロップステップを調整することができます、すべての要素をすべての範囲にドロップしないで、いくつかのsli dingウィンドウ。 Nを配列の要素の量とすると、ウィンドウの幅はwとなり、各ステップでoffで移動します。その後、off*(N-1) + wは範囲の合計幅になります。

      ここでは、要素の位置を歪ませますが、完全にはランダムではありません。

      function weak_shuffle($a, $strength) { 
          $len = count($a); 
          if ($len <= 1) return $a; 
          $out = array(); 
          $M = mt_getrandmax(); 
          $w = round($M/($strength + 1)); // width of the sliding window 
          $off = ($M - $w)/($len - 1); // offset of that window for each step. 
          for ($i = 0; $i < $len; $i++) { 
           do { 
            $idx = intval($off * $i + mt_rand(0, $w)); 
           } while(array_key_exists($idx, $out)); 
           $out[$idx] = $a[$i]; 
          } 
          ksort($out); 
          return array_values($out); 
      } 
      
      • $strength = 0〜通常のシャッフル。
      • $strength = 0.25〜ご希望の結果(40.5%、25.5%、22%、elephant 12%)
      • $strength = 1最初の項目が最後の後になることはありません。
      • $strength >= 3配列が実際にテストのための遊び場

      をシャッフルされることはありません:

      $animals = array('elephant', 'dog', 'cat', 'mouse'); 
      $pos = array(0,0,0,0); 
      for ($iter = 0; $iter < 100000; $iter++) { 
          $shuffled = weak_shuffle($animals, 0.25); 
          $idx = array_search('elephant', $shuffled); 
          $pos[$idx]++; 
      } 
      print_r($pos); 
      
    +0

    +1、非常に良いアプローチ。それは非決定論的な実行時間を持っていることが残念です。 – Jon

    +0

    @Jonまず、 'mt_getrandmax'は2^31-1を返します。したがって、小さな配列では* conflicts *はほとんどありません。第2に、同じキー結果を解決することは、決定論的な順序で実行されることがあります。例えば。 'FIFO'または同じキーを持つすべての値を配列に集めてからシャッフルしてください;-) – kirilloid

    +0

    本当に巧妙な解決策であり、私の目的に役立つ@Kirilloidをありがとうございます。あなたはそれにも力を与えることさえできます。 –

    2

    てみてください、このアルゴリズムを使用する:

    $animals = [ 'elephant', 'dog', 'cat', 'mouse' ]; // you can add more animals here 
    $shuffled = []; 
    
    $count = count($animals); 
    
    foreach($animals as $chance => $animal) { 
        $priority = ceil(($count - $chance) * 100/$count); 
        $shuffled = array_merge($shuffled, array_fill(0, $priority, $animal)); 
    } 
    
    shuffle($shuffled); 
    $animals = array_unique($shuffled); 
    
    1

    あなたは配列を持っている、のは、n個の要素から言わせて。 i番目の要素がj番目の位置に行く確率はP(i、j)です。私はよく理解した場合、以下の式が成り立つ:

    (P(i1, j1) >= P(i2, j2)) <=> (|i1 - j1| <= |j1 - i1|) 
    

    をこのように、あなたは、アレイ内の距離とシャッフル確率とガロア接続を持っています。このGalois接続を使用して、正確な数式があれば実装することができます。数式がない場合は、上記の基準を満たす数式を作成できます。がんばろう。

    関連する問題