Array Comparison 1

JavaScript performance comparison

Revision 2 of this test case created by Bergi

Preparation code

 
<script>
Benchmark.prototype.setup = function() {
    var a = [];
    var b = [];
    var arr = [];
    var obj = {};
    var max = 10000;
   
    for (var i = 0; i < max; i++) {
      if (i % 20) {
        b[max - i - 1] = arr;
        a[i] = arr;
      }
      else if( i % 10 ) {
        b[ max - i - 1] = obj;
        a[i] = obj;
      }
      else {
        b[ max - i - 1] = i;
        a[i] = i;
      }
    }
   
    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 (b.indexOf(a[i]) === -1) return false;
        }
        // if both types are not the same then this array
        // contains different number of primitives
        else {
          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;
    }
};
</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…
Bruno
sameElementsBruno(a, b);
pending…
Hamidi
sameElementsHamidi(a, b)
pending…
Bergi
sameElementsBergi(a, b)
pending…

Compare results of other browsers

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:

0 comments

Add a comment