Board index   FAQ   Search  
Register  Login
Board index php forum :: php coding PHP coding => General

Random quote generator idea

Ask about general coding issues or problems here.

Moderators: macek, egami, gesf

Random quote generator idea

Postby determined » Tue Nov 18, 2003 11:58 pm

I have been toying around with a random number generator to serve up quotes from a table in mysql. In this I was not pleased by the way that my quotes were shown. The problem was, and yes you can call me anal, that the quotes would sometimes repeat themselves. This is not good to me, seeing that any time this happens the user, depending on their computer skill, is going to be annoyed and or baffled if it repeats more than two times, and every time they click their refresh button they are creating more hits that are unnecessary.

To solve this what I did was created an array containing a randomly sorted list of all of the quotes, then I randomly pick one of the quotes and display it. After displaying the quote, I delete it out of the array, and put the new array in a SESSION var so it can be used for next refresh. If the number of quotes in the array gets down lower than two it regenerates a randomly sorted array of quotes.

Now there are very few repeats but there are still some when you change arrays. The last one can match the first you get when you refresh arrays, and I cant keep track of this without putting ids on the quotes.

Anyway I am interested in hearing about other methods to do this and similar tasks, if any one knows of any.
User avatar
determined
New php-forum User
New php-forum User
 
Posts: 23
Joined: Sun Sep 28, 2003 12:19 pm
Location: Table Arizona

Re: Random quote generator idea

Postby swirlee » Wed Nov 19, 2003 12:31 am

Interesting problem. Reminds me of another thread that's floating around here. This is a "shuffle" problem rather than a "random" problem, really. What I'd do is this: Put the quotes in a database. This isn't necessary, but it's how I think. Give the quotes table three columns: id (INT), last_picked (DATE), and quote (TEXT). id can be your usual id field -- no need to randomize or anything. When you first populate the table, just use NOW() for last_picked. Then, build a second table -- this is a bit of waste, though, as it's only going to have two columns and one row, ever (unless you have more than one set of quotes at some point): Call it reset, and give it an id field and a field called date (DATE). Insert a row with id 1 and value NOW() in date (ensure that this is a date after the latest date in the quotes table).

Now, write your script like so: Randomly SELECT a quote with a last_picked date that's EARLIER than the date in last_reset:

Code: Select all
SELECT id, quote FROM quotes, reset WHERE reset.id = 1 AND quote.last_picked < reset.date ORDER BY RAND() LIMIT 1;


So you've got a random quote -- print it out and remember the id number. Now do a second query: count the number of rows in quotes that have a last_picked date that's EARLIER than the date in last_reset:

Code: Select all
SELECT COUNT(id) AS num_left FROM quotes, reset WHERE reset.id = 1 AND quote.last_picked < reset.date;


IF num_left is 1, then you've only got one quote left, and it's the one you just printed out. Which means it's time to reset the list. So do an UPDATE on reset:

Code: Select all
UPDATE reset SET reset.date = NOW() WHERE id = 1;


Lastly, you have to mark the quote you just picked as having been just picked, so the date is after reset.date:

Code: Select all
UPDATE quotes SET last_picked = NOW() WHERE id = $id;
# Where $id is the ID of the just-chosen quote


Now all of the quotes will have a last_picked date that's EARLIER (I don't know why I keep capitalizing that) than reset.date EXCEPT for the one you just printed -- e.g. the last quote printed in the previous "cycle" won't get printed, at the earliest, until the next time you reset the list, or one full cycle later. That might be a bit excessive, but it will ensure that you won't print the same quote twice. If that's not important to you, then you can switch around the order of the queries and test for 0 quotes left instead of 1. This approach, though, saves you a lot of writing to the database: where other approaches might require you to move quotes from one database or another, this one requires you to write to just one field most of the time.

But I'm not sure if it's optimal. I'll have to think about it a bit more. The above is more of a knee-jerk reaction to your question. I don't know if it'd really pan out in the end.
User avatar
swirlee
Moderator
Moderator
 
Posts: 2272
Joined: Sat Jul 05, 2003 1:18 pm
Location: A bunk in the back

Postby determined » Sun Nov 23, 2003 1:23 am

I liked your idea, but decided to not mess around with the tables any more than necessary.

Take a look. It is random, but it does not repeat itself. Also any number of users can access it at once.
Code: Select all
function random_quote() {
   determined_db_connect();
   if (!isset($_SESSION[random_quotes]) || ($_SESSION[counter] == $_SESSION[num_rows])) {
      $_SESSION[counter] = "0";
      $quote_ids = mysql_query("SELECT DISTINCT quotes_id FROM quotes WHERE quotes_id != '$_SESSION[last_quote]'");
      $_SESSION[num_rows] = mysql_num_rows($quote_ids);
      if ($_SESSION[num_rows] > "0") {
         while ($quoteidrow = mysql_fetch_array($quote_ids, MYSQL_ASSOC)) {
            $random_quotes[] = $quoteidrow[quotes_id];
         }
         for ($ids = count($random_quotes); --$ids; $ids > 0) {
            $j = @mt_rand(0, $ids+1);
            $temp = $random_quotes[$ids];
            $random_quotes[$ids] = $random_quotes[$j];
            $random_quotes[$j] = $temp;
         }
         $_SESSION[random_quotes] = $random_quotes;
      }
   }
   $counter = $_SESSION[counter];
   $random_id = $_SESSION[random_quotes][$counter];
   determined_db_connect();
   $random_quote = mysql_query("SELECT DISTINCT * FROM quotes WHERE quotes_id = '$random_id'");
   $quote_num_rows = mysql_num_rows($random_quote);
   if ($quote_num_rows > "0") {
      
      while ($print_row = mysql_fetch_array($random_quote, MYSQL_ASSOC)) {
         print '"' . stripslashes($print_row[quote]) . '"<br>--' . stripslashes($print_row[author]);
      }
   }
   $_SESSION[last_quote] = $random_id;
   $_SESSION[counter]++;
}


The only problem it has is with multiple calls on the same page, the counter will bump up as many times as you call it because of the session counter, otherwise I have no problems as of yet.

Im interested to hear what you think of this array shuffler.
Code: Select all
for ($ids = count($random_quotes); --$ids; $ids > 0) {
            $j = @mt_rand(0, $ids+1);
            $temp = $random_quotes[$ids];
            $random_quotes[$ids] = $random_quotes[$j];
            $random_quotes[$j] = $temp;
         }
User avatar
determined
New php-forum User
New php-forum User
 
Posts: 23
Joined: Sun Sep 28, 2003 12:19 pm
Location: Table Arizona

Re: Random quote generator idea

Postby Redcircle » Mon Nov 24, 2003 10:07 am

swirlee wrote:Interesting problem. Reminds me of another thread that's floating around here. This is a "shuffle" problem rather than a "random" problem, really. What I'd do is this: Put the quotes in a database. This isn't necessary, but it's how I think. Give the quotes table three columns: id (INT), last_picked (DATE), and quote (TEXT). id can be your usual id field -- no need to randomize or anything. When you first populate the table, just use NOW() for last_picked. Then, build a second table -- this is a bit of waste, though, as it's only going to have two columns and one row, ever (unless you have more than one set of quotes at some point): Call it reset, and give it an id field and a field called date (DATE). Insert a row with id 1 and value NOW() in date (ensure that this is a date after the latest date in the quotes table).


Hrmm never though of this method.
User avatar
Redcircle
Moderator
Moderator
 
Posts: 830
Joined: Tue Jan 21, 2003 10:42 pm
Location: Michigan USA


Return to PHP coding => General

Who is online

Users browsing this forum: No registered users and 2 guests

Sponsored by Sitebuilder Web hosting and Traduzioni Italiano Rumeno and antispam for cPanel.