59

I have a list:

<ul>
    <li>milk</li>
    <li>butter</li>
    <li>eggs</li>
    <li>orange juice</li>
    <li>bananas</li>
</ul>

Using javascript how can I reorder the list items randomly?

2
  • possible duplicate of jquery move elements into a random order Commented Aug 15, 2011 at 20:00
  • 12
    @Pekka It doesn't look like he's using jQuery. Commented Aug 15, 2011 at 20:05

8 Answers 8

128
var ul = document.querySelector('ul');
for (var i = ul.children.length; i >= 0; i--) {
    ul.appendChild(ul.children[Math.random() * i | 0]);
}

This is based on Fisher–Yates shuffle, and exploits the fact that when you append a node, it's moved from its old place.

Performance is within 10% of shuffling a detached copy even on huge lists (100 000 elements).

http://jsfiddle.net/qEM8B/

Sign up to request clarification or add additional context in comments.

3 Comments

For a large set of items, it's recommended to shuffle a copy of the element in JS and then copy it back to the DOM, as-is. DEMO - jsbin.com/jiboxuru/1/edit
@vsync thanks for the edit, but I've rolled it back, because the loop doesn't need "+ 1" added to children.length. Rounding length down gives the largest index.
it's the same number of characters ;) but you're right. jsbin.com/jiboxuru/3/edit
11

Simply put, like this:

JS:

var list = document.getElementById("something"),
button = document.getElementById("shuffle");
function shuffle(items)
{
    var cached = items.slice(0), temp, i = cached.length, rand;
    while(--i)
    {
        rand = Math.floor(i * Math.random());
        temp = cached[rand];
        cached[rand] = cached[i];
        cached[i] = temp;
    }
    return cached;
}
function shuffleNodes()
{
    var nodes = list.children, i = 0;
    nodes = Array.prototype.slice.call(nodes);
    nodes = shuffle(nodes);
    while(i < nodes.length)
    {
        list.appendChild(nodes[i]);
        ++i;
    }
}
button.onclick = shuffleNodes;

HTML:

<ul id="something">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<button id="shuffle" type="button">Shuffle List Items</button>

Demo: http://jsbin.com/itesir/edit#preview

4 Comments

If someone can come up with a more lightweight solution, I would be grateful and accept their answer. Thanks!
I wouldn't call 26 lines of code "large". You're going to have a very difficult time finding something smaller.
How come the HTML doesn't need a reference to the script (except in IE apparently)?
26 lines of code is insane. better answered by Alexey Lebedev.
1
    var list = document.getElementById("something");
    function shuffleNodes() {
        var nodes = list.children, i = 0;
        nodes = Array.prototype.sort.call(nodes);
        while(i < nodes.length) {
           list.appendChild(nodes[i]);
           ++i;
        }
    }
    shuffleNodes();

Comments

0

Based no @Alexey Lebedev's answer, if you prefer a jQuery function that shuffles elements, you can use this one:

$.fn.randomize = function(selector){
  var $elems = selector ? $(this).find(selector) : $(this).children();
  for (var i = $elems.length; i >= 0; i--) {
    $(this).append($elems[Math.random() * i | 0]);
  }

  return this;
}

And then call it like this:

$("ul").randomize();        //shuffle all the ul children
$("ul").randomize(".item"); //shuffle all the .item elements inside the ul
$(".my-list").randomize(".my-element"); //shuffle all the .my-element elements inside the .my-list element.

1 Comment

@Glapa could you provide an example?
0

Here is a very simple way to shuffle with JS:

var points = [40, 100, 1, 5, 25, 10];
points.sort(function(a, b){return 0.5 - Math.random()});

http://www.w3schools.com/js/js_array_sort.asp

1 Comment

This sort is biased, not all permutations of elements are equally likely. More info here: bost.ocks.org/mike/algorithms/#shuffling
0

I was searching for a prototype function. Maybe this helps someone.

Element.prototype.shuffleChildren = function() {
  for (var i = this.children.length; i >= 0; i--) {
    this.appendChild(this.children[Math.random() * i | 0]);
  }
};

document.querySelector('body').shuffleChildren();

Comments

0

Use this:

function htmlShuffle(elem) {
    function shuffle(arr) {
        var len = arr.length;
        var d = len;
        var array = [];
        var k, i;
        for (i = 0; i < d; i++) {
            k = Math.floor(Math.random() * len);
            array.push(arr[k]);
            arr.splice(k, 1);
            len = arr.length;
        }
        for (i = 0; i < d; i++) {
            arr[i] = array[i];
        }
        return arr;
    }
    var el = document.querySelectorAll(elem + " *");
    document.querySelector(elem).innerHTML = "";
    
    let pos = [];
    for (let i = 0; i < el.length; i++) {
        pos.push(i);
    }
    
    pos = shuffle(pos);
    for (let i = 0; i < pos.length; i++) {
        document.querySelector(elem).appendChild(el[pos[i]]);
    }
}

htmlShuffle("ul");
<ul>
    <li>milk</li>
    <li>butter</li>
    <li>eggs</li>
    <li>orange juice</li>
    <li>bananas</li>
</ul>

Comments

0

Here's a solution that does not use a loop.

function shuffle_children(element) {
    element.append(...Array.from(element.children).sort(function () {
        return Math.random() - 0.5;
    }));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.