Jump to content

when random() is too random


mindplay.dk
 Share

Recommended Posts

WireArray::getRandom() can be "too" random for my taste - I wanted some Page items to rotate randomly on a daily basis, rather than every page load, so I came up with this:

 /**
  * Select random pages from a PageArray
  *
  * If no $seed is provided, today's date is used to seed the random number
  * generator, so you can use this function to rotate items on a daily basis.
  *
  * @param PageArray $pages the list of Page object to select from
  * @param int $amount the amount of items to extract from the given list
  * @param int|null $seed a number used to see the random number generator
  */
 public function randomPages(PageArray $pages, $amount=1, $seed=null)
 {
   if ($seed === null) {
  $seed = crc32(date('Ymd'));
   }

   srand($seed);

   $keys = $pages->getKeys();

   $selected = new PageArray();

   while (count($keys) > 0 && count($selected) < $amount) {
  $index = rand(0, count($keys)-1);

  $key = $keys[$index];

  $selected->add($pages[$key]);

  array_splice($keys, $index, 1);
   }

   return $selected;
 }

I thought I would post it here for others to use. I wonder if this is useful enough that it (or something similar) should be part of the core?

I personally find that "totally random" is rarely useful or desirable in real life - for one, pages that change on every request may harm your search-engine ranking. For another, users may find it confusing that your site changes all the time - "hey, what was that thing I just saw" doesn't work for the person who goes back to the front-page to see "that other thing" he just saw, when you constantly swap things out between every page view...

Just my opinion, for what it's worth :)

  • Like 1
Link to comment
Share on other sites

Perhaps even better:

 /**
  * Select random pages from a PageArray
  *
  * If no $seed is provided, today's date is used to seed the random number
  * generator, so you can use this function to rotate items on a daily basis.
  *
  * @param PageArray $pages the list of Page object to select from
  * @param int $amount the amount of items to extract from the given list
  * @param int|string $seed a number used to see the random number generator; or a string compatible with date()
  */
 public function randomPages(PageArray $pages, $amount=1, $seed='Ymd')
 {
   if (is_string($seed)) {
  $seed = crc32(date($seed));
   }

   srand($seed);

   $keys = $pages->getKeys();

   $selected = new PageArray();

   while (count($keys) > 0 && count($selected) < $amount) {
  $index = rand(0, count($keys)-1);

  $key = $keys[$index];

  $selected->add($pages[$key]);

  array_splice($keys, $index, 1);
   }

   return $selected;
 }

Now you can seed with a date()-compatible string, so you can rotate weekly (for example) using "YW", or monthly using "Ym", etc.

  • Like 5
Link to comment
Share on other sites

I agree this does seem really useful, thanks for posting it. I can think of a lot of situations where I really should be using this rather than the existing getRandom(). Rather than adding to PageArray, it seems like the value could extend further than just pages and perhaps it belongs in WireArray instead? (which would be inherited by PageArray)

I'm thinking name should be: getRandomInterval(), getRandomTimed() ... or some name that alludes to what differentiates it from getRandom()?

Link to comment
Share on other sites

For the most part, I usually prefer more functions to more arguments. This is one reason why I've never been too happy with that second $alwaysArray argument to the current getRandom() function. I should have had just getRandom() that always returns 1, and findRandom() that always returns a WireArray/PageArray.

So while it could be added to getRandom(); I think the value of it might be easy for people to miss, because it'd be a 3rd argument. So here's what I did instead:

https://github.com/r...329a491e9d77b0a

See the new functions added: findRandom() and findRandomTimed(). Adding the findRandom() function helps to get the API clarity it was missing before, and gives findRandomTimed() more context. Of course, getRandom() will still return more than 1 if you tell it to, as I wouldn't want to break compatibility. But if I could go back in time, I would make getRandom() always return 1 and have no arguments.

Link to comment
Share on other sites

Seeded is a more accurate description I agree. But for me the concern is the term... how many people know what "seeded" means? :) I went back and forth on it a few times, but since the default behavior is to return a random result within a timed/daily period, I figured we'd let the function describe the default behavior. The advanced people will be able to figure out how to make it do something different, whereas the non-advanced people might completely miss the big value in this function otherwise. I could be wrong, but am guessing 99% of the time, people would be using this function in a timed fashion rather than some other kind of seed? At least, I haven't been able to think of other scenarios yet.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...