theintellects
theintellects

Reputation: 1370

How to go through an unknown number of quotes randomly without repeating

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);
});

Upvotes: 1

Views: 203

Answers (4)

elclanrs
elclanrs

Reputation: 94101

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

Upvotes: 2

6502
6502

Reputation: 114491

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.

Upvotes: 0

RobG
RobG

Reputation: 147413

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];
  }
}());

Upvotes: 0

dave
dave

Reputation: 64657

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.

Upvotes: 0

Related Questions