11

I have a list if divs which contain images. I need to randomly show 4 of these each time the page loads. Here's the code I'm starting with.

<div class="Image"><img src="/image1.jpg"></div>
<div class="Image"><img src="/image2.jpg"></div>
<div class="Image"><img src="/image3.jpg"></div>
<div class="Image"><img src="/image4.jpg"></div>
<div class="Image"><img src="/image5.jpg"></div>
<div class="Image"><img src="/image6.jpg"></div>
<div class="Image"><img src="/image7.jpg"></div>

All of these will start as display:none, I'd like to take 4 of the divs at random and set them to display:block. I'm assuming I need to use "Math.random()" in there somewhere but not sure how JQuery does this. Any pointers would be appreciated.

Mike Muller
  • 2,257
  • 6
  • 32
  • 33

3 Answers3

18

I find sorting them randomly then showing the first 4 to be the easiest, like this:

var divs = $("div.Image").get().sort(function(){ 
            return Math.round(Math.random())-0.5; //so we get the right +/- combo
           }).slice(0,4);
$(divs).show();

You can test it out here. If you want to also randomize the order (not just which are shown), you already have them sorted so just append them to the same parent in their new order by changing this:

$(divs).show();
//to this:
$(divs).appendTo(divs[0].parentNode).show();

You can test that version here.

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 1
    Nice one, slicing at the array to avoid processing more than necessary, and adding the appendTo. – Phrogz Nov 17 '10 at 14:31
  • Sorting the array using that technique is biased towards the original positions (more likely to show the first four), but that is probably fine for the poster's needs. – Phrogz Nov 17 '10 at 14:35
  • @Phrogz - It shouldn't be, that's what the `-0.5` is for, to make the result `-0.5` or `0.5` giving a forward/back sort for all elements, not a `0, 1` which would be forward only...giving the first elements bias. – Nick Craver Nov 17 '10 at 14:40
  • 3
    Apparently the bias depends on the `sort` implementation. I've made [a test](http://phrogz.net/JS/JavaScript_Random_Array_Sort.html) to show the difference. The results on Firefox (3.6 and 4.0b7) on OS X range from 3.1% to 24.6%. Chrome is worse, ranging from 0.8% to 29.2%. Safari 4 inverts the bias and fares batter, varying only from 7.4% to 17.8%. All of them show even distribution using a pre-computed sort key, however. – Phrogz Nov 17 '10 at 16:31
3

This does what you need: http://www.jsfiddle.net/Yn2pn/1/

$(document).ready(function() {
    $(".Image").hide();

    var elements = $(".Image");
    var elementCount = elements.size();
    var elementsToShow = 4;
    var alreadyChoosen = ",";
    var i = 0;
    while (i < elementsToShow) {
        var rand = Math.floor(Math.random() * elementCount);
        if (alreadyChoosen.indexOf("," + rand + ",") < 0) {
            alreadyChoosen += rand + ",";
            elements.eq(rand).show();
            ++i;
        }
    }
});
Vincent Mimoun-Prat
  • 28,208
  • 16
  • 81
  • 124
2
jQuery(function($){
  var sortByN = function(a,b){ a=a.n; b=b.n; return a<b?-1:a>b?1:0 };
  $.each( $('div.Image').map(
    function(){ return { div:this, n:Math.random() }; }
  ).get().sort(sortByN), function(i){
    if (i<4) $(this.div).show();
  });
});

Note that this will always show the divs in the same order as the original. Is that acceptable?

Phrogz
  • 296,393
  • 112
  • 651
  • 745