0

リセットするまで、範囲から呼び出すたびにランダムな一意のペア番号を返す関数を書きたいと思います。このようなもの:

function randomUniquePairs($ranges, $reset = false){
   if ($reset === false){
      // some code for reseting
   }
   /*
     some code for creating random unique pair numbers
   */
   return $result;  
} 

randomUniquePairs(range(1,10), range(1,20));
/*
  this function returns for example:
   array(2,9)
*/
randomUniquePairs(range(1,10), range(1,20));
/*
  this function returns for example:
   array(5,19)
*/

randomUniquePairs(range(1,10), range(1,20));
/*
  this function returns for example:
   array(5,19)
*/
 //this function returns random unique pairs until we pass reset paramer true

私は2つのアプローチを試みます:

1) 可能なペアをすべて作成し、それらからランダムに選択しますが、範囲が非常に広い場合、多くのメモリを消費するため、非常に非効率的です。コード:

  class a {
    private $asqar;

    function __construct() ($range) {

        // cycle for ranges
        foreach ($range[0] as  $v1) {
            foreach ($range[1] as $v2) {
                $asqar[] =  array(
                    $v1,
                    $v2,
                );
            }
        }
    }

    function randomUniquePairs($reset = false){

        if ($reset === true){
           $this->asgar = array();
        }

        $rndKey = array_rand($this->asgar);
        $result = $this->asqar[$rndkey];
        unset($this->asqar[$rndkey]);
        return $result;
    }
}

$c = new a(range(1,10), range(1,20));
$c->randomUniquePairs();

2)2番目は、これらの範囲からペアを生成する関数を作成し、それを変数に格納します。ペアを生成した後にその関数が呼び出されるたびに、関数を再帰的に呼び出す前にこのペアが生成されたかどうかを確認し、一意の値を生成するまで続行しますペア。このコード:

class a{ 

    private $__uniqueVariables = array();

    public function randomUniquePairs($range, $reset = false) {

        if ($reset === true){
       $this->__uniqueVariables = array();
    }

    // cycle for each value
    foreach ($range as $value) {

        // shuffle
        shuffle($value);

        // selected id
        $selectedId[] = $value[0];
    }

    // check for selected variable
    if (in_array($rndUnqNum, $this->__uniqueVariables)) {

        // return for try again
        return $this->uniqueVariable($range);
    }

    // added to current unique variables
    $this->__uniqueVariables[] = $rndUnqNum;

    // return
    return $rndUnqNum;
}

}

しかし、これには時々スローする問題がありFatal error: Maximum function nesting level of '100' reachedます。

もっと良いアルゴリズムが欲しい。

4

1 に答える 1

1

これは広い範囲でもうまくいくようです:

rand() 関数は、上記の例のように、値の配列を作成または操作することなく、指定された範囲でランダムな整数を取得する優れた方法です。

更新 停止ケースを追加しました (履歴が可能な最大の一意のペア以上の場合、空の配列が返されます)。そのコードを自由に変更して、範囲を自動的にリセットしてください。

<?php
class c {

    function c($min_X,$max_X,$min_Y,$max_Y) {
        $this->setRange($min_X,$max_X,$min_Y,$max_Y);
    }

    function getRandUniquePair($reset = false) {
        if ($reset) {
            $this->__history = array();
        }

        if (count($this->__history) >= $this->__max_pairs) {
            return array();
        }

        $candidate = array(rand($this->__range[0],$this->__range[1]),rand($this->__range[2],$this->__range[3]));

        if (in_array($candidate,$this->__history)) {
            return $this->getRandUniquePair();
        }

        $this->__history[] = $candidate;

        return $candidate;
    }

    function setRange($min_X,$max_X,$min_Y,$max_Y) {
        $this->__range = array($min_X,$max_X,$min_Y,$max_Y);
        $this->__max_pairs = ($max_X - $min_X) * ($max_Y - $min_Y);
        $this->__history = array();
    }
}

// test

$c = new c(0,10,0,20);

$i = 0;
$pairs = array();
while ($i < 100) {
    $i++;
    $pair = $c->getRandUniquePair();

    if (in_array($pair,$pairs)) {
        die('Duplicate pairs!');
    }

    echo $pair[0].', '.$pair[1]."\n";
    $pairs[] = $pair;
}

$c->setRange(0,100000000000,0,100000000000);
echo "I perform well even at large ranges!\n";

$i = 0;
while ($i < 1000) {
    $i++;
    $pair = $c->getRandUniquePair();

    echo $pair[0].', '.$pair[1]."\n";
}

?>
于 2013-07-26T02:18:33.107 に答える