# Array Comparison 1

## JavaScript performance comparison

Revision 11 of this test case created

## Preparation code

`` <script>  Benchmark.prototype.setup = function() {    var a = [];    var b = [];    var obj;    var arr;    var max = 10000;        for (var i = 0; i < max; i++) {      if (i % 5) {        arr = [1, 2];        b[max - i - 1] = arr;        a[i] = arr;      } else if (i % 2) {        obj = {          "hello": "world"        };        b[max - i - 1] = obj;        a[i] = obj;      } else {        b[max - i - 1] = i % 100;        a[i] = i % 100;      }    }        function sameElementsBrunoLM(a, b) {      // immediately discard if they are of different sizes      if (a.length != b.length) return false;          b = b.slice(0); // clone to keep original values after the function      a.forEach(function(e) {        var i;        if ((i = b.indexOf(e)) != -1) b.splice(i, 1);      });          return !b.length;    }        function sameElementsBruno(a, b) {          // if length is not the same then must not be equal      if (a.length != b.length) return false;          // do an initial sort which will group types      a.sort();      b.sort();          for (var i = 0; i < a.length; i++) {            // if primitive then comparison will do        if (isPrimitive(a[i]) && isPrimitive(b[i])) {              if (a[i] != b[i]) return false;        }        // if not primitive then we will need to check for obj ref        else if (!isPrimitive(a[i]) && !isPrimitive(b[i])) {          if (!a[i].__aCount) a[i].__aCount = 0;          if (!b[i].__bCount) b[i].__bCount = 0;          a[i].__aCount = a[i].__aCount + 1;          b[i].__bCount = b[i].__bCount + 1;        }        // if both types are not the same then this array        // contains different number of primitives        else {          return false;        }          }      for (var i = 0; i < a.length; i++) {        if (!isPrimitive(a[i])) {          if (!a[i].__aCount) {            return false;          }          if (!a[i].__bCount) {            return false;          }          if (a[i].__aCount != a[i].__bCount) {            return false;          }        }      }      // if it gets this far it must be the same      return true;    }        function isPrimitive(arg) {      var type = typeof arg;      return arg == null || (type != "object" && type != "function");    }        function sameElementsHamidi(a, b) {      if (a.length != b.length) {        return false;      }      var ourB = b.concat();      return a.every(function(item) {        var index = ourB.indexOf(item);        if (index < 0) {          return false;        } else {          ourB.splice(index, 1);          return true;        }      });    }        function sameElementsBergi(a) {      var map, maps = [],                                                                                          // counting booleans, numbers and strings          nulls = [],                                                                                          // counting undefined and null          nans = [],                                                                                          // counting nans          objs, counts, objects = [],          al = arguments.length;      // quick escapes:      if (al < 2) return true;      var l0 = a.length;      if ([].slice.call(arguments).some(function(s) {        return s.length != l0;      })) return false;          for (var i = 0; i < al; i++) {        var multiset = arguments[i];        maps.push(map = {}); // better: Object.create(null);        objects.push({          vals: objs = [],          count: counts = []        });        nulls[i] = 0;        nans[i] = 0;        for (var j = 0; j < l0; j++) {          var val = multiset[j];          if (val !== val) nans[i]++;          else if (val === null) nulls[i]++;          else if (Object(val) === val) { // non-primitive            var ind = objs.indexOf(val);            if (ind > -1) counts[ind]++;            else objs.push(val), counts.push(1);          } else { // booleans, strings and numbers do compare together            if (typeof val == "boolean") val = +val;            if (val in map) map[val]++;            else map[val] = 1;          }        }      }          // testing if nulls and nans are the same everywhere      for (var i = 1; i < al; i++)      if (nulls[i] != nulls[0] || nans[i] != nans[0]) return false;          // testing if primitives were the same everywhere      var map0 = maps[0];      for (var el in map0)      for (var i = 1; i < al; i++) {        if (map0[el] !== maps[i][el]) return false;        delete maps[i][el];      }      for (var i = 1; i < al; i++)      for (var el in maps[i])      return false;          // testing of objects were the same everywhere      var objs0 = objects[0].vals,          ol = objs0.length;      counts0 = objects[0].count;      for (var i = 1; i < al; i++)      if (objects[i].count.length != ol) return false;      for (var i = 0; i < ol; i++)      for (var j = 1; j < al; j++)      if (objects[j].count[objects[j].vals.indexOf(objs0[i])] != counts0[i]) return false;          // else, the multisets are equal:      return true;    }        function mapTypes(a) {          var _map = {};          for (var i = 0; i < a.length; i++) {            var _t = toType(a[i]);        if (keyGen.hasOwnProperty(_t)) {          _t = _t + keyGen[_t](a[i]);        }            if (!_map[_t]) {          _map[_t] = [];        }            _map[_t].push(i);      }          return _map;    }        function mapTypesMatch(mapA, mapB) {      var a = Object.keys(mapA);      var b = Object.keys(mapB);          if (a.length != b.length) return false;          for (var i = 0; i < a.length; i++) {            if (!mapB[a[i]]) return false;        if (mapA[a[i]].length != mapB[a[i]].length) return false;      }          return true;    }            function arrayElementsMatch(mapA, sourceA, mapB, sourceB) {          for (var key in mapA) {        if (mapA.hasOwnProperty(key)) {              for (var i = 0; i < mapA[key].length; i++) {            var found = false;            for (var k = 0; k < mapB[key].length; k++) {              if (sourceA[mapA[key][i]] === sourceB[mapB[key][k]]) {                mapB[key].slice(k, 1);                found = true;                break;              }            }            if (!found) return false;          }        }      }          return true;    }            var keyGen = {      "[object Object]": function(obj) {        return Object.keys(obj).length;      },      "[object Array]": function(arr) {        return arr.length;      },      "[object Date]": function(d) {        return d.getYear();      },      "[object Number]": function(n) {        return n.toString().length;      },      "[object String]": function(str) {        return str.length;      }    }        var toType = function(obj) {        return Object.prototype.toString.call(obj);        }                                                                                    function sameElementsBruno2(a, b) {          if (a.length != b.length) return false;          var mapA = mapTypes(a);      var mapB = mapTypes(b);          if (!mapTypesMatch(mapA, mapB)) return false;      if (!arrayElementsMatch(mapA, a, mapB, b)) return false;          return true;    }        function sameElementsBruno3(a, b) {        var objs = [];        // if length is not the same then must not be equal        if (a.length != b.length) return false;            // do an initial sort which will group types        a.sort();        b.sort();            for ( var i = 0; i < a.length; i++ ) {                var aIsPrimitive = isPrimitive(a[i]);            var bIsPrimitive = isPrimitive(b[i]);                // NaN will not equal itself            if( a[i] !== a[i] ) {                if( b[i] === b[i] ) {                    return false;                }            }            else if (aIsPrimitive && bIsPrimitive) {                    if( a[i] != b[i] ) return false;            }            // if not primitive increment the __count property            else if (!aIsPrimitive && !bIsPrimitive) {                incrementCountA(a[i]);                incrementCountB(b[i]);                // keep track on non-primitive objects                objs.push(i);            }            // if both types are not the same then this array            // contains different number of primitives            else {                return false;            }            }            var result = true;            for (var i = 0; i < objs.length; i++) {            var ind = objs[i];            if( a[ind].__aCount !== a[ind].__bCount ) result = false;            if( b[ind].__aCount !== b[ind].__bCount ) result = false;                // revert object to what it was             // before entering this function            delete a[ind].__aCount;            delete a[ind].__bCount;            delete b[ind].__aCount;            delete b[ind].__bCount;        }            return result;    }        // inspired by @Bergi's code    function isPrimitive(arg) {        return Object(arg) !== arg;    }        function incrementCountA(arg) {        if (arg.hasOwnProperty("__aCount")) {            arg.__aCount = arg.__aCount + 1;        } else {            Object.defineProperty(arg, "__aCount", {                enumerable: false,                value: 1,                writable: true,                configurable: true            });        }    }    function incrementCountB(arg) {        if (arg.hasOwnProperty("__bCount")) {            arg.__bCount = arg.__bCount + 1;        } else {            Object.defineProperty(arg, "__bCount", {                enumerable: false,                value: 1,                writable: true,                configurable: true            });        }    }                  function sameElementsTHG(a, b) {        var hash = function(x) {            return typeof x + (typeof x == "object" ? a.indexOf(x) : x);            }                                            return a.map(hash).sort().join() == b.map(hash).sort().join();      }  };</script>``

## Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
BrunoLM
``sameElementsBrunoLM(a, b);``
pending…
Hamidi
``sameElementsHamidi(a, b)``
pending…
Bergi
``sameElementsBergi(a, b)``
pending…
Bruno
``sameElementsBruno3(a, b);``
pending…
THG
``sameElementsTHG(a, b)``
pending…

## Revisions

You can edit these tests or add even more tests to this page by appending `/edit` to the URL. Here’s a list of current revisions for this page: