Array shuffle comparator (on small array) (v14)

Revision 14 of this benchmark created on


Preparation HTML

<!-- add a library -->
<script src="http://underscorejs.org/underscore.js"></script>

<!-- define all functions, etc -->
<script>
	// make the test array in the first place
	var testArray = [];
	for (var i = 0; i < 100; i++) {
		testArray[i] = i;
	}


	// a generic shuffle function ("mezclar" is "to mix" in spanish?)
	Array.prototype.mezclar = function () {
		var n = this.length;
		while (n--) {
			var i = Math.floor(n * Math.random());
			var tmp = this[i];
			this[i] = this[n];
			this[n] = tmp;

		}
		return this;
	}

	// same thing, compressed loop into for declaration
	var mezclar2 = function (arr) {
		for (var i, tmp, n = arr.length; n; i = Math.floor(Math.random() * n), tmp = arr[--n], arr[n] = arr[i], arr[i] = tmp);
		return arr;
	}


	// same as mezclar2, only as prototype fn
	Array.prototype.mezclar3 = function () {
		for (var i, tmp, n = this.length; n--; i = Math.floor(Math.random() * n), tmp = this[i], this[i] = this[n], this[n] = tmp);
		return this;
	}

	// yet another generic implementation, from http://jsperf.com/shuffle-optimization-00129393
	Array.prototype.shuffle1 = function () {
		var l = this.length + 1;
		while (l--) {
			var r = ~~(Math.random() * l),
				o = this[r];

			this[r] = this[0];
			this[0] = o;
		}

		return this;
	}

	// again, another generic implementation that almost the same from http://jsperf.com/shuffle-optimization-00129393
	Array.prototype.shuffle2 = function () {
		var len = this.length;
		var i = len;
		while (i--) {
			var p = parseInt(Math.random() * len);
			var t = this[i];
			this[i] = this[p];
			this[p] = t;
		}

		return this;
	};

	// http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html
	function NaiveShuffle(arr) {
		var i, temp, j, len = arr.length;
		for (i = 0; i < len; i++) {
			j = ~~(Math.random() * len);
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
		return arr;
	}

	// http://www.codinghorror.com/blog/2007/12/the-danger-of-naivete.html
	function knuthfisheryates(arr) {
		var i, temp, j, len = arr.length;
		for (i = 0; i < len; i++) {
			j = ~~(Math.random() * (i + 1));
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}
		return arr;
	}

	// kfy - min
	function fy(a,b,c,d){//array,placeholder,placeholder,placeholder
	 c=a.length;while(c)b=Math.random()*c--|0,d=a[c],a[c]=a[b],a[b]=d;return a
	}

	// http://stackoverflow.com/a/2450976/1037948
	function knuthfisheryates2(arr) {
		var temp, j, i = arr.length;
		while (--i) {
			j = ~~(Math.random() * (i + 1));
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}

		return arr;
	}

	// same as above, moved +1 outside loop
	function knuthfisheryates2b(arr) {
		var temp, j, i = arr.length+1;
		while (--i) {
			j = ~~(Math.random() * i);
			temp = arr[i];
			arr[i] = arr[j];
			arr[j] = temp;
		}

		return arr;
	}
</script>


<i>Example output from methods.</i>
<div id="debug"></div>
<script>

	// and a smaller test for confirming that they're actually shuffling - see console

	if (/*console && console.log &&*/ JSON && JSON.stringify) {
    smallTestArray = [
	{ value: 11, img: '1.png', name: 'Ac' },
	{ value: 11, img: '2.png', name: 'As' },
	{ value: 11, img: '3.png', name: 'Ah' },
	{ value: 11, img: '4.png', name: 'Ad' },
	{ value: 10, img: '5.png', name: 'Kc' },
	{ value: 10, img: '6.png', name: 'Ks' },
	{ value: 10, img: '7.png', name: 'Kh' },
	{ value: 10, img: '8.png', name: 'Kd' },
	{ value: 10, img: '9.png', name: 'Qc' },
	{ value: 10, img: '10.png', name: 'Qs' },
	{ value: 10, img: '11.png', name: 'Qh' },
	{ value: 10, img: '12.png', name: 'Qd' },
	{ value: 10, img: '13.png', name: 'Jc' },
	{ value: 10, img: '14.png', name: 'Js' },
	{ value: 10, img: '15.png', name: 'Jh' },
	{ value: 10, img: '16.png', name: 'Jd' },
	{ value: 10, img: '17.png', name: '10c' },
	{ value: 10, img: '18.png', name: '10s' },
	{ value: 10, img: '19.png', name: '10h' },
	{ value: 10, img: '20.png', name: '10d' },
	{ value: 9, img: '21.png', name: '9c' },
	{ value: 9, img: '22.png', name: '9s' },
	{ value: 9, img: '23.png', name: '9h' },
	{ value: 9, img: '24.png', name: '9d' },
	{ value: 8, img: '25.png', name: '8c' },
	{ value: 8, img: '26.png', name: '8s' },
	{ value: 8, img: '27.png', name: '8h' },
	{ value: 8, img: '28.png', name: '8d' },
	{ value: 7, img: '29.png', name: '7c' },
	{ value: 7, img: '30.png', name: '7s' },
	{ value: 7, img: '31.png', name: '7h' },
	{ value: 7, img: '32.png', name: '7d' },
	{ value: 6, img: '33.png', name: '6c' },
	{ value: 6, img: '34.png', name: '6s' },
	{ value: 6, img: '35.png', name: '6h' },
	{ value: 6, img: '36.png', name: '6d' },
	{ value: 5, img: '37.png', name: '5c' },
	{ value: 5, img: '38.png', name: '5s' },
	{ value: 5, img: '39.png', name: '5h' },
	{ value: 5, img: '40.png', name: '5d' },
	{ value: 4, img: '41.png', name: '4c' },
	{ value: 4, img: '42.png', name: '4s' },
	{ value: 4, img: '43.png', name: '4h' },
	{ value: 4, img: '44.png', name: '4d' },
	{ value: 3, img: '45.png', name: '3c' },
	{ value: 3, img: '46.png', name: '3s' },
	{ value: 3, img: '47.png', name: '3h' },
	{ value: 3, img: '48.png', name: '3d' },
	{ value: 2, img: '49.png', name: '2c' },
	{ value: 2, img: '50.png', name: '2s' },
	{ value: 2, img: '51.png', name: '2h' },
	{ value: 2, img: '52.png', name: '2d' }
];


		var $debug = document.getElementById('debug');
		function debugWrite() {
			//console.log.apply(Array.prototype.slice.call(arguments, 0));
			$debug.innerHTML += "\n\n<p>\n";
			for (var a in arguments) {
				if( arguments.hasOwnProperty(a) )
					$debug.innerHTML += arguments[a].toString() + "\n &nbsp; &nbsp; \n";
			}
			$debug.innerHTML += "</p>\n\n";
		}

		function debugTest(testname, arr, operation) {
			debugWrite('-------');
			//console.log('  arr before ', JSON.stringify(arr));
			debugWrite(testname, ': results: ', JSON.stringify(operation(arr)));
			// console.log('  arr after', arr);
		}

		debugWrite('Initial Array:', JSON.stringify(smallTestArray));

		debugTest('mezclar', smallTestArray, function (o) { return o.mezclar(); });
		debugTest('mezclar as for', smallTestArray, function (o) { return mezclar2(o); });
		debugTest('mezclar for as prototype', smallTestArray, function (o) { return o.mezclar3(); });
		debugTest('native', smallTestArray, function (o) { return o.sort(function () { return 0.5 - Math.random() }); });
		debugTest('generic1', smallTestArray, function (o) { return o.shuffle1(); });
		debugTest('generic2', smallTestArray, function (o) { return o.shuffle2(); });
		debugTest('naive', smallTestArray, function (o) { return NaiveShuffle(o); });
		debugTest('fisheryates1', smallTestArray, function (o) { return knuthfisheryates(o); });
		debugTest('fisheryates2', smallTestArray, function (o) { return knuthfisheryates2(o); });
		debugTest('fy', smallTestArray, function (o) { return fy(o); });
		debugTest('underscore', smallTestArray, function (o) { return _.shuffle(o); });
		debugTest('fisheryates2b', smallTestArray, function (o) { return knuthfisheryates2b(o); });


	}
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
marlanga's version
testArray.mezclar();
ready
marlanga as for-loop
mezclar2(testArray);
ready
marlanga for-loop as prototype
testArray.mezclar3();
ready
Native sort with callback
testArray.sort(function() {
  return 0.5 - Math.random()
});
ready
Generic Shuffle1
testArray.shuffle1();
ready
Generic Shuffle 2
testArray.shuffle2();
ready
Naive Shuffle
NaiveShuffle(testArray);
ready
Knuth-Fisher-Yates as for
knuthfisheryates(testArray);
ready
Knuth-Fisher-Yates as while
knuthfisheryates2(testArray);
ready
Knuth-Fisher-Yates as while, v2
knuthfisheryates2b(testArray);
ready
underscore
_.shuffle(testArray)
ready
coco's minified Fisher-Yates
fy(testArray);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.