Any way to shuffle content in multiple div elements

12,702

Solution 1

are you ok with using a javascript library like jQuery? here's a quick jQuery example to accomplish what you're after. the only modification to your HTML is the addition of a container element as suggested:

<div id="shuffle">
    <div id='d1'>...</div>
    <div id='d2'>...</div>
    <div id='d3'>...</div>
</div>

and javascript:

function shuffle(e) {               // pass the divs to the function
    var replace = $('<div>');
    var size = e.size();

    while (size >= 1) {
       var rand = Math.floor(Math.random() * size);
       var temp = e.get(rand);      // grab a random div from our set
       replace.append(temp);        // add the selected div to our new set
       e = e.not(temp); // remove our selected div from the main set
       size--;
    }
    $('#shuffle').html(replace.html() );     // update our container div with the
                                             // new, randomized divs
}

shuffle( $('#shuffle div') );

Solution 2

A recent question was just closed as duplicate of this, but I feel I've got a better answer than any here. This method is very direct. There's no mucking with copying HTML, thus preserving changes to the DOM, styles, event handlers, etc.

To shuffle all the children of some parent element, select a random child and append it back to the parent one at a time until all the children have been re-appended.

Using jQuery:

var parent = $("#shuffle");
var divs = parent.children();
while (divs.length) {
    parent.append(divs.splice(Math.floor(Math.random() * divs.length), 1)[0]);
}

Demo: http://jsfiddle.net/C6LPY/2

Without jQuery it's similar and just as simple:

var parent = document.getElementById("shuffle");
var divs = parent.children;
var frag = document.createDocumentFragment();
while (divs.length) {
    frag.appendChild(divs[Math.floor(Math.random() * divs.length)]);
}
parent.appendChild(frag);

Demo: http://jsfiddle.net/C6LPY/5/



Edit: Here's a break down of the code:

// Create a document fragment to hold the shuffled elements
var frag = document.createDocumentFragment();

// Loop until every element is moved out of the parent and into the document fragment
while (divs.length) {

    // select one random child element and move it into the document fragment
    frag.appendChild(divs[Math.floor(Math.random() * divs.length)]);
}

// appending the document fragment appends all the elements, in the shuffled order
parent.appendChild(frag);

Solution 3

You can grab the content of each div

c1 = document.getElementById('div1').innerHTML
c2 = document.getElementById('div2').innerHTML
c3 = document.getElementById('div3').innerHTML

Then determine a new order for them randomly .. and then put each content in the new destination

say for instance, the randomness gave:

c1_div = 'div2'
c2_div = 'div1'
c3_div = 'div3'

then you just:

document.getElementById(c1_div).innerHTML = c1
document.getElementById(c2_div).innerHTML = c2
document.getElementById(c3_div).innerHTML = c3

Solution 4

Expanding on the nice answer by @gilly3, using jQuery one can actually avoid appending randomly-chosen elements of divs in a loop, by randomly sorting divinstead and appending them all at once:

$(function() {
  var parent = $("#shuffle");
  var divs = parent.children();
  divs.sort(function(a, b) {
    return 0.5 - Math.random();
  });
  parent.append(divs);
});

Demo: http://jsfiddle.net/ey70Lxhk/

Note however that this technique is not accurate in terms of randomness, and relies on sort which does not scale linearly with the number of elements.

Share:
12,702
Chris
Author by

Chris

Updated on June 12, 2022

Comments

  • Chris
    Chris almost 2 years

    I'm relatively new to Javascript and was wondering if there's a quick way to shuffle content that is contained in multiple <div> tags. For example

    <div id='d1'>
      <span>alpha</span>
      <img src='alpha.jpg'>
    </div>
    <div id='d2'>
      <span>beta</span>
      <img src='beta.jpg'>
    </div>
    <div id='d3'>
      <span>gamma</span>
      <img src='gamma.jpg'>
    </div>
    
    <button onclick='shuffle_content();'>Shuffle</button>
    

    After clicking on the button, I'd like the content in d1, d2, d3 to change places (for example maybe d3 would be first, then d1, then d2).

    A quick way to kind of move things around is to copy the first div element (d1), then put it at the very end (after d3), and then delete the original d1. But that doesn't really randomize things. It just makes things go in the cycle (which might be ok).

    Any suggestions would be appreciated. Thanks.

  • Joel Anair
    Joel Anair over 15 years
    This doesn't answer the question, just explains a different way to move the content.
  • Rob Allen
    Rob Allen over 15 years
    I offered a quick way to move the content around which is the OP's original intent. What did you read the question to ask?
  • Chris
    Chris over 15 years
    Thanks Owen, I think this is best answer I've seen so far.
  • Chris
    Chris over 15 years
    Unfortunately, since my reputation is below 15, I can't vote this up. But if I could, I would.
  • Chris
    Chris about 12 years
    Good answer. If Stackoverflow allowed questions to have multiple "accepted" answers, I would also label this as "accepted".
  • user962206
    user962206 about 12 years
    is this also applicable for shuffling list?
  • user962206
    user962206 about 12 years
    @gilly3 A question on "divs.splice(Math.floor(Math.random() * divs.length), 1)[0]" what is the use of [0] ?
  • gilly3
    gilly3 about 12 years
    @user962206 - .splice() returns an array containing, in this case, a single element. [0] gets you the first element in that array.
  • gilly3
    gilly3 about 12 years
    @user962206 - yes, you can use this to shuffle a list of any kind of element.
  • user962206
    user962206 about 12 years
    But splice removes the content right? and returns the removed items?
  • gilly3
    gilly3 about 12 years
    @user962206 - Yes, that's the point. Notice the while loop... we loop until the Array is empty and all the elements have been re-inserted.
  • gilly3
    gilly3 about 12 years
    @user962206 - I've updated my answer with a breakdown of the exactly what's happening inside the while loop. I hope that helps to clarify it for you.
  • user962206
    user962206 about 12 years
    when will the loop actually stop? aren't the loop going to stop since there would be always one entry or one item in the divs array?
  • gilly3
    gilly3 about 12 years
    @user962206 - No, remember .splice() removes the item from the array. Since in each iteration of the while loop we remove exactly one item from the array, the loop will end as soon as we have processed each element. divs is an Array whose elements reference dom nodes. We created that array by copying the elements from the parent element's children collection. Removing an element from the array does not modify the DOM. Ie, calling divs.splice(n, 1) removes an element from the Array, but the element still exists in the page as a child of parent.