2016-07-21 7 views
1

私はデータベースから単語のリストを取得しようとしていますが、$ word1。$ word2。$ word3の形式で独自の3単語の組み合わせを作成し、それを星に割り当てます。単語の表からランダムに3単語の組み合わせが重複しないようにするにはどうすればよいですか?

私は重複した組み合わせを避けたい - 私は、各星に一意の3語の識別子を持たせたい。

私の現在の方法では、すべての可能な3語の組み合わせの配列を作成し、それから星に割り当てられた配列から各組み合わせを削除します。しかし、私の単語リストには数千語を使うつもりです。つまり、この配列には数千億もの組み合わせが含まれていることになるので、この方法は非常に非効率的です。

これをより効果的に達成するにはどうすればよいですか?私の最初の考えは、私は各星をループし、3ワードの組み合わせを作成して割り当て、次に配列にコンボを追加し、各星について新しく生成されたコンボが配列に含まれているかどうかを確認することです。

コード

<?php 

    // Initiate connection to the database... 
    $db = mysqli_connect('localhost', 'root', '', 'stellar'); 

    // Query database of words 
    $words_sql = "SELECT * FROM words"; 
    $words_res = mysqli_query($db, $words_sql)or die(mysqli_error()); 

    // Create array of words 
    $words = array(); 

    // Loop through each word from the database and add each to an array 
    while($row = mysqli_fetch_array($words_res)){ 
     $words[] = $row['word']; 
    } 

    // Create array of all possible three-word combinations, from which we will randomly select our combinations 
    $triplets = array(); 
    foreach ($words as $word1){ 
     foreach ($words as $word2){ 
      foreach($words as $word3){ 
       if ($word1 !== $word2 && $word2 !== $word3 && $word1 !== $word3){ 
        $triplets[] = "$word1.$word2.$word3"; 
       } 
      }  
     } 
    } 

    // Pull all stars from database 
    $stars_sql = "SELECT * FROM stars"; 
    $stars_res = mysqli_query($db, $stars_sql)or die(mysqli_error()); 

    // Loop through every star in the array 
    while($row = mysqli_fetch_array($stars_res)){ 
     // Store the star name and star_id in variables 
     $star = $row['star_name']; 
     $star_id = $row['star_id']; 

     // Set $three_words as a random combination from the array of possible combinations... 
     $ran_num  = array_rand($triplets); 
     $three_words = $triplets[$ran_num]; 

     // ...and remove this particular combination, in order to prevent repating combinations 
     array_splice($triplets, $ran_num, 1); 

     // Attach the random 3-word combination to the star 
     echo $star.'&nbsp;&nbsp;&nbsp;&nbsp;'.$three_words.'<br/><br/>'; 
    } 
?> 
+0

1000語の場合、1000000000通りの組み合わせがあります。名前を付ける必要のある星の総数と比較してどのように表示されますか?たとえば、100万個以上の星が500000000個ありますか? – apokryfos

+0

私は〜250万星から始めたいので、〜300単語しか必要ないと思います。 – Callum

答えて

1

はMySQLがあなたのために重い物を持ち上げるの一部を行うために取得することができますマイナーな微調整は、(おそらく)があります。

$words_sql = "SELECT CONCAT(w1.word,'.',w2.word,'.',w3.word) as triplet 
FROM (words w1 JOIN words w2 ON w1.word != w2.word) 
    JOIN words w3 ON w3.word != w1.word AND w3.word != w2.word"; 
$words_res = mysqli_query($db, $words_sql)or die(mysqli_error()); 

// Create array of words 
$words = array(); 

// Loop through each word from the database and add each to an array 
while($row = mysqli_fetch_array($words_res)){ 
    $triplets[] = $row['triplet']; 
} 

これはおそらく、あなたが三つ子を事前に生成したり、後でそれらを生成するかどうかを意味し、あなたがスターへのすべてのトリプレットが割り当てられていますプロセスの終了であるため取得するつもりだとして良いですとにかくそれらをすべて生成することになります。

トリプレットの数が名前のついた星の数よりはるかに多い場合の代替ソリューションがあります:250万星、2000語(または80億のトリプレット)があるとします。あなたは次の操作を行うことができますので、この場合には星があなたの可能三つ子のほんの一部です:第2のケースで

$words = array(); 

// Loop through each word from the database and add each to an array 
while($row = mysqli_fetch_array($words_res)){ 
    $words[] = $row['word']; 
} 

// Pull all stars from database 
$stars_sql = "SELECT * FROM stars"; 
$stars_res = mysqli_query($db, $stars_sql)or die(mysqli_error()); 

// Loop through every star in the array 
$used = []; 
while($row = mysqli_fetch_array($stars_res)){ 
    // Store the star name and star_id in variables 
    $star = $row['star_name']; 
    $star_id = $row['star_id']; 

    do { 
     //Generate non-repeating triplet of words (sample without replacement?) 
     $word1 = array_rand($words); 
     do { 
      $word2 = array_rand($words); 
     } while ($word2 == $word1); 

     do { 
      $word3 = array_rand($words); 
     } while ($word3 == $word2 || $word1 == $word3); 

     $triplet = $words[$word1].".".$words[$word2].".".$words[$word3]; 
    } while (isset($used[$triplet])); //Try again if we've already used it. Very unlikely. 

    $used[$triplet] = true; //Keep track of what we've used. 
    echo $star.'&nbsp;&nbsp;&nbsp;&nbsp;'.$triplet.'<br/><br/>';  
} 

を私たちは同じトリプレットを生成する機会が二度あるため可能で非常に小さいので、これは動作しますトリプレットの数と、私たちが合計でそれらのうちのほんのわずかしか使用していないという事実。

+0

あなたの答えをありがとう! スクリプトが既に生成されているトリプレットを作成すると、同じ星のために$ word1、$ word2、$ word3を何度も繰り返し作成するという無限ループに陥ります。 私はそれを修正できるかどうか確認するためにそれを試してみるつもりです。私は10,000の星と2,272の言葉を使っています。 array_rand()関数はあまりランダムではないようです。私はあなたの考えを感謝します。 – Callum

+0

[OK]を修正しました。代わりに、$ max = count($ words)と$ min = $ max - $ maxを設定してrandom_int($ min、$ max)関数を使用しました。このスクリプトは〜2秒で10,000個のユニークな組み合わせを生成して印刷するようになりました。 ご協力いただきありがとうございます。 – Callum

関連する問題