2016-07-21 5 views
1

Ich versuche, eine Liste von Wörtern aus der Datenbank zu ziehen, eine eindeutige Drei-Wort-Kombination in der Form $ word1. $ Word2. $ Word3 zu erstellen und sie einem Stern zuzuordnen.Wie kann ich doppelte zufällige Drei-Wort-Kombinationen aus einer Tabelle von Wörtern vermeiden?

Ich möchte doppelte Kombinationen vermeiden - ich möchte, dass jeder Stern eine eindeutige Drei-Wort-Kennung hat.

Meine aktuelle Methode besteht darin, ein Array aller möglichen Drei-Wort-Kombinationen zu erstellen und dann jede Kombination aus dem Array zu löschen, sobald sie einem Stern zugewiesen wurde. Ich beabsichtige jedoch, ein paar tausend Wörter in meiner Wortliste zu verwenden, was bedeutet, dass dieses Array Zehntausende von Kombinationen enthält, so dass diese Methode unglaublich ineffizient erscheint.

Wie kann ich dies effektiver erreichen? Meine anfänglichen Gedanken sind, dass ich jeden Stern durchlaufen, eine Drei-Wort-Kombination erstellen und zuweisen, dann die Kombination zu einem Array hinzufügen und für jeden Stern überprüfen soll, ob die neu erzeugte Kombination im Array ist.

-Code

<?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

Wenn Sie 1000 Wörter haben, hätten Sie 1000000000 mögliche Kombinationen. Wie ist das mit den Sternen zu vergleichen, die Sie benennen müssen, z. B. 100 Sterne oder mehr wie 500000000 Sterne? – apokryfos

+0

Ich möchte mit ~ 2,5 Millionen Sternen beginnen, also denke ich, dass ich nur ~ 300 Wörter benötige. – Callum

Antwort

1

Es ist (möglicherweise) eine kleine zwicken Sie MySQL einige schweres Heben zu tun für Sie machen können, zu erhalten.

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

Dies ist wahrscheinlich so gut wie Sie, weil am Ende des Prozesses zu bekommen sind Sie alle Tripletts zu einem Stern zugewiesen werden, was bedeutet, ob Sie die Drillinge vorab erzeugen oder sie später erzeugen Am Ende wirst du sie alle generieren.

Jetzt gibt es eine alternative Lösung für den Fall, wo die Anzahl der Tripel viel größer ist als die Anzahl der Sterne, die Sie benennen müssen: sagen Sie haben 2,5 Millionen Sterne, aber 2000 Wörter (oder 8 Milliarden Tripel). In diesem Fall sind die Sterne einen winzigen Bruchteil der möglichen Drillinge sind, so dass Sie die folgenden Aktionen durchführen:

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

Im zweiten Fall funktioniert dies, weil die Chance, dass wir die gleiche Triplett zweimal sehr klein ist wegen der möglichen erzeugen Anzahl der Drillinge und die Tatsache, dass wir nur einen winzigen Teil von ihnen verwenden.

+0

Danke für Ihre Antwort! Was passiert, ist, dass, wenn das Skript ein Triplet erzeugt, das bereits erzeugt wurde, es in eine Endlosschleife fällt, $ word1, $ word2 und $ word3 immer wieder für denselben Stern zu erzeugen. Ich werde mit ihm spielen, um zu sehen, ob ich es beheben kann. Ich benutze 10.000 Sterne und 2.272 Wörter. Es scheint, dass die Funktion array_rand() nicht sehr zufällig ist. Ich würde mich über Ihre Gedanken freuen. – Callum

+0

Ok, repariere es. Ich habe stattdessen die Funktion random_int ($ min, $ max) verwendet und $ max = count ($ words) und $ min = $ max - $ max gesetzt. Das Skript generiert und druckt nun 10.000 eindeutige Kombinationen in ~ 2 Sekunden. Vielen Dank für Ihre Hilfe. – Callum

Verwandte Themen