# Array Comparison 1

## JavaScript performance comparison

Revision 15 of this test case created by C5H8NNaO4

## 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();    }                    Object.defineProperty(Boolean.prototype, "equals", {      enumerable: false,      configurable: true,      value: function(c) {        return this == c;      }    });        Object.defineProperty(Number.prototype, "equals", {      enumerable: false,      configurable: true,      value: Boolean.prototype.equals    });    Object.defineProperty(String.prototype, "equals", {      enumerable: false,      configurable: true,      value: Boolean.prototype.equals    });        Object.defineProperty(Object.prototype, "equals", {      enumerable: false,      configurable: true,      value: function(c, reference) {        if (true === reference) return this === c;        if (typeof this != typeof c) {          return false;        }        var d = [Object.keys(this), Object.keys(c)],            f = d[0].length;        if (f !== d[1].length) {          return false;        }        for (var e = 0; e < f; e++) {          if (d[0][e] != d[1][e] || !this[d[0][e]].equals(c[d[1][e]])) {            return false;          }        }        return true;      }    });    Object.defineProperty(Array.prototype, "equals", {      enumerable: false,      configurable: true,      value: function(c, reference) {            var d = this.length;        if (d != c.length) {          return false;        }        var f = Array.prototype.equals.sort(this.concat());        c = Array.prototype.equals.sort(c.concat(),f)        if (reference) {          for (var e = 0; e < d; e++) {            if (f[e] != c[e]) {              return false;            }          }        } else {          for (var e = 0; e < d; e++) {            if (!f[e].equals(c[e], reference)) {              return false;            }          }        }        return true;          }    });    Object.defineProperty(Array.prototype.equals, "sort", {      enumerable: false,      value: function sort (curr,prev) {             var weight = {                "[object Undefined]":6,                         "[object Object]":5,                "[object Null]":4,                "[object String]":3,                "[object Number]":2,                "[object Boolean]":1            }            if (prev) { //mark the objects                for (var i = prev.length,j,t;i>0;i--) {                    t = typeof (j = prev[i]);                    if (j != null && t === "object") {                         j._pos = i;                       } else if (t !== "object" && t != "undefined" ) break;                }            }                    curr.sort (sorter);                        if (prev) {                for (var k = prev.length,l,t;k>0;k--) {                    t = typeof (l = prev[k]);                    if (t === "object" && l != null) {                        delete l._pos;                    } else if (t !== "object" && t != "undefined" ) break;                }            }            return curr;                    function sorter (a,b) {                         var tStr = Object.prototype.toString                 var types = [tStr.call(a),tStr.call(b)]                 var ret = [0,0];                 if (types[0] === types[1] && types[0] === "[object Object]") {                     if (prev) return a._pos - b._pos                     else {                         return a === b ? 0 : 1;                     }                 } else if (types [0] !== types [1]){                         return weight[types[0]] - weight[types[1]]                 }                                                         return a>b?1:a<b?-1:0;            }                }            });        function sameElementsGlutamat(c, d , referenceCheck) {      return c.equals(d, referenceCheck);    }  };</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…
Glutamat (deep check)
``sameElementsGlutamat (a,b)``
pending…
Glutamat (reference check)
``sameElementsGlutamat (a,b,true)``
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: