【问题标题】:How can I avoid duplicate random three-word combinations from a table of words?如何避免单词表中重复的随机三个单词组合?
【发布时间】:2016-07-22 20:01:14
【问题描述】:

我正在尝试从数据库中提取单词列表,以 $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/>';
    }
?>

【问题讨论】:

  • 如果您有 1000 个单词,您将有 1000000000 个可能的组合,这与您需要命名的总星数相比如何,例如,它是像 100 个星还是更多像 500000000 个星?
  • 我想从大约 250 万颗星开始,所以我想我只需要大约 300 个字。

标签: php random combinations


【解决方案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/>';      
 } 

在第二种情况下,这是可行的,因为我们生成相同的三元组两次的机会非常小,因为可能存在三元组的数量,而且我们总共只使用了其中的一小部分。

【讨论】:

  • 感谢您的回答!似乎正在发生的事情是,当脚本创建一个已经生成的三元组时,它陷入了为同一个星星一遍又一遍地创建 $word1、$word2 和 $word3 的无限循环。我要去玩它,看看我能不能修复它。我使用了 10,000 颗星和 2,272 个单词。看起来 array_rand() 函数不是很随机。如果您有任何想法,我将不胜感激。
  • 好的,修好了。我改用 random_int($min, $max) 函数,设置 $max = count($words) 和 $min = $max - $max。该脚本现在在约 2 秒内生成并打印 10,000 个独特的组合。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-20
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多