1

I have a small snippet of Javascript where I rotate through a list of quotes in order from beginning to end.

However, I want to randomly go through the list (instead of in order), without repeating until all of the quotes are iterated through, and then start around with a random quote again. How would I go about doing this?

$(function(){
    var quotes = $('#quotes').children('.rotate-quote');
    firstQuo = quotes.filter(':first');
    lastQuo = quotes.filter(':last');
    quotes.first().show();
    setInterval(function(){
        if($(lastQuo).is(':visible')) {
            var nextElem = $(firstQuo);
        } else {
            var nextElem = $(quotes).filter(':visible').next();
        }
        $(quotes).filter(':visible').fadeOut(300);
        if($(lastQuo).is(':visible')) {
            setTimeout(function() {
                $(firstQuo).fadeIn(300);
            }, 600);

        } else {
            setTimeout(function() {
                $(nextElem).fadeIn(600);
            }, 600);
        }
    }, 10000);
});
theintellects
  • 1,320
  • 2
  • 16
  • 28
  • You seem to be essentially asking [this question](http://stackoverflow.com/questions/6625551/jquery-math-random-number-without-repeating-a-previous-number). – ajp15243 May 20 '13 at 05:02
  • 1
    [Fisher Yates](http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle) – Ja͢ck May 20 '13 at 05:04
  • @Jack Thanks for the name to the solution! I can never quite remember names to specific problems... – theintellects May 20 '13 at 05:40

4 Answers4

2

Here's a possible solution with demo:

var $container = $('div'),
    quotes = $('quote').hide().toArray(),
    delay = 500;

function shuffle(arr) {
  return arr.map(function(v){ return [v,Math.random()]; })
    .sort().map(function(v){ return v[0]; });
}

function loop() {
  $(shuffle(quotes)).each(function(i,el) {
    setTimeout(function(){ $(el).appendTo($container).show(); }, i*delay);
  });
}

function start() {
  function begin(){ $(quotes).hide(); loop(); }
  setInterval(begin, quotes.length * delay);
  begin();
}

start();

Demo: http://jsbin.com/agihix/1/edit

Edit: I turned this into a little plugin, grab it here https://gist.github.com/elclanrs/5610886

elclanrs
  • 92,861
  • 21
  • 134
  • 171
  • Very cool demo! Made it easy for me to see it working, now I'll just steal a bit of your code and change it a bit to work for mine. Thanks! – theintellects May 20 '13 at 05:39
0

Just to show the Fisher Yates (not my code):

function fisherYates ( myArray ) {
  var i = myArray.length, j, temp;
  if ( i === 0 ) return false;
  while ( --i ) {
     j = Math.floor( Math.random() * ( i + 1 ) );
     temp = myArray[i];
     myArray[i] = myArray[j]; 
     myArray[j] = temp;
  }
  return myArray;
}

So get your quotes into an array, run it through that function, then do loop through the array, when you get to the end, run it through that function again, etc.

dave
  • 62,300
  • 5
  • 72
  • 93
0

The following copies the quote array, then randomly slices one from it each time. wWen there are no entries left, it starts again.

var randomQuote = (function() {
  var quotes = ['quote 0','quote 1','quote 2'];
  var quoteCopy = [];

  return function () {
    if (!quoteCopy.length) {
      quoteCopy = quotes.slice();
    }
    return quoteCopy.splice(Math.random()*quoteCopy.length | 0, 1)[0];
  }
}());
RobG
  • 142,382
  • 31
  • 172
  • 209
0

I don't think your algorithm as stated is good. Suppose you have 100 quotes and then you make a first random presentation of the full set.

At the end, as stated in your description, will start again from scratch and so it's possible that quote 101 will be the same quote as 100.

I think that something better (more uniform) would be

  1. Randomly shuffle the n quotes. This is done only once at the beginning.
  2. Pick the first quote and display it.
  3. Remove the quote from the list and insert it in a random position between n-w and n where w is a parameter (e.g. n/2).
  4. Repeat from 2 for each quote you need.

The number w will modulate how much random you want the sequence to be... the smaller and the more uniform the delay will be after a quote is presented.

With this approach there will be no "distribution glitch" and the average delay after which a quote is presented next time will not depend on the current position.

6502
  • 112,025
  • 15
  • 165
  • 265
  • True, I did consider this for a bit, but realistically, who's going to wait for all 100 quotes to finish displaying? (: Thanks for adding to the discussion though! – theintellects May 20 '13 at 06:58
  • @theintellects: I've thought about this problem while running because the random shuffle of my N1 android phone was truly terrible. I think the algorithm is "as next one pick a random song and play it" and this, thanks to an horrible PRNG, was really bad. – 6502 May 20 '13 at 07:06