如何避免 table 个单词中出现重复的随机三单词组合?
How can I avoid duplicate random three-word combinations from a table of words?
我正在尝试从数据库中提取单词列表,以 $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.' '.$three_words.'<br/><br/>';
}
?>
您可以(可能)进行一些小调整,让 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.' '.$triplet.'<br/><br/>';
}
在第二种情况下,这是可行的,因为我们两次生成相同三元组的机会非常小,因为三元组的可能数量以及我们只使用它们的一小部分这一事实。
我正在尝试从数据库中提取单词列表,以 $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.' '.$three_words.'<br/><br/>';
}
?>
您可以(可能)进行一些小调整,让 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.' '.$triplet.'<br/><br/>';
}
在第二种情况下,这是可行的,因为我们两次生成相同三元组的机会非常小,因为三元组的可能数量以及我们只使用它们的一小部分这一事实。