58

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?

Web_Designer
  • 72,308
  • 93
  • 206
  • 262

8 Answers8

121
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/

Alexey Lebedev
  • 11,988
  • 4
  • 39
  • 47
  • 1
    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 - http://jsbin.com/jiboxuru/1/edit – vsync Mar 10 '14 at 13:50
  • @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. – Alexey Lebedev Mar 10 '14 at 14:22
  • 1
    it's the same number of characters ;) but you're right. http://jsbin.com/jiboxuru/3/edit – vsync Mar 10 '14 at 15:06
12

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

  • 1
    If someone can come up with a more lightweight solution, I would be grateful and accept their answer. Thanks! – Web_Designer Aug 15 '11 at 21:11
  • 3
    I wouldn't call 26 lines of code "large". You're going to have a very difficult time finding something smaller. –  Aug 15 '11 at 21:34
  • How come the HTML doesn't need a reference to the script (except in IE apparently)? – shim Dec 29 '12 at 23:51
  • 26 lines of code is insane. better answered by Alexey Lebedev. – vsync Mar 10 '14 at 13:35
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();
Stefan Gruenwald
  • 2,582
  • 24
  • 30
1

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>
Blackjack
  • 1,322
  • 1
  • 16
  • 21
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

  • 2
    This sort is biased, not all permutations of elements are equally likely. More info here: https://bost.ocks.org/mike/algorithms/#shuffling – Alexey Lebedev Feb 02 '17 at 09:07
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();
Fred
  • 868
  • 10
  • 22
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;
    }));
}
diachedelic
  • 2,195
  • 1
  • 24
  • 28
-1

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.
Gustavo G.
  • 79
  • 1
  • 7