Shuffle and pagination combo

Hello, I need to shuffle and then paginate a collection. Basically it should be as simple as this:

$collection->shuffle()->paginate(10)

But this gives me some random duplicates of items on different pagination pages.

When I use shuffle without pagination, it works just like expected, also when I use only pagination, it works just fine. Is there a way I can use both shuffle and pagination at the same time, without duplicating some of the content?

Thanks!

Have you tried…

$collection->paginate(10)->shuffle()

This should shuffle each page, i think, instead of shuffling the whole set.

Well yes, but it does slightly different thing, not what I need.

This paginates the items, and then shuffles each page separately. Which results in minimal variation. On the first page of pagination, there are alwas the same items, only in different order. I would like to have always different set of items on the first page (and other pages), in different order… complete randomness, without some weird duplication.

I think ive got an idea whats going on here. Those are not duplicates. Whats happening is that when you load each page, its reshuffling the whole set which means at some point you end up hitting items you have already seen. Make sense?

You need a way to do the shuffle on the first page of the pagination and have it persist through the pages.

I’m learning PHP so forgive the stab at this but try using a session, something like this.

if(!isset($_SESSION['random_pages'])){
    $_SESSION['random_pages'] = 1;
    $randompages = $collection->shuffle();
}

Then pick up on the $randompages variable in your pagination. This should run the shuffle just once if hasn’t already run, and I think work across multiple pages. Someone with better PHP knowledge please correct me…

Totally makes sense… unfortunately :slight_smile:

What I need is to do the shuffle once, and then paginate this shuffled set… but have no idea if something like this is posiible.

EDIT: Thanks for the code, will try it.

Make sure thats available to every page in the pagination, not just the first page, because you cant be sure that is where a user will start. For instance, they might come in on page four from a google search result. Basically you need set the shuffled collection just once, regardless of what page they arrive on.

This should help you understand sessions.

I think what you need is some kind of shuffle with a specific seed.
The seed should get stored in a cookie or session so you have the same randomness in every following page request.

I put something together. It can be optimized but it works and you get the idea :wink:.

// site/plugins/shuffleOnce.php

// shuffle pages by a session based seed or supply a seed
pages::$methods['shuffleOnce'] = function($pages, $seed = null) {
  if(is_null($seed)) {
    $seed = s::get('seed');

    if(is_null($seed)) {
      $seed = time();
      s::set('seed', $seed);
    }
  }

  mt_srand($seed);

  $keys = array_keys($pages->data);
  $size = count($keys);

  for($i = 0; $i < $size; ++$i) {
    list($chunk) = array_splice($keys, mt_rand(0, $size - 1), 1);
    array_push($keys, $chunk);
  }

  $collection = clone $pages;
  $collection->data = array();
  foreach($keys as $key) {
    $collection->data[$key] = $pages->data[$key];
  }

  return $collection;
};
// use a session based seed
foreach($pages->shuffleOnce()->paginate(10) as $p) {
  echo $p->title()->html();
}

// or supply your own seed if necessary
foreach($pages->shuffleOnce(123456789)->paginate(10) as $p) {
  echo $p->title()->html();
}
2 Likes

@jimbobrjames @lukaskleinschmidt Thank you very much, now I know what the problem is and hopefully have an idea how to fix it.