如何从单词表中避免重复的随机三字组合?

时间:2016-07-21 15:55:03

标签: php random combinations

我正在尝试从数据库中提取单词列表,以$ word1。$ word2。$ word3的形式创建一个唯一的三字组合,并将其分配给一个星号。

我想避免重复组合 - 我希望每个星都有一个独特的三字标识符。

我当前的方法涉及创建一个包含所有可能的三字组合的数组,然后在将数组分配给星形后从数组中删除每个组合。但是,我打算在我的单词列表中使用几千个单词,这意味着这个数组将包含数百亿个组合,所以这种方法看起来非常低效。

如何更有效地实现这一目标?我最初的想法是,我应该遍历每个星,创建并分配一个三字组合,然后将组合添加到一个数组,并为每个星,检查新生成的组合是否在数组中。

代码

 <?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/>';
    }
?>

1 个答案:

答案 0 :(得分: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亿三胞胎)。在这种情况下,星星只是你可能的三胞胎的一小部分,所以你可以做到以下几点:

$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/>';      
 } 

在第二种情况下,这是有效的,因为我们两次生成相同三元组的机会非常小,因为可能的三元组数量以及我们总共只使用它们中的一小部分这一事实。