Skip to content

Instantly share code, notes, and snippets.

@bobrik
Created July 11, 2012 10:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bobrik/3089440 to your computer and use it in GitHub Desktop.
Save bobrik/3089440 to your computer and use it in GitHub Desktop.
lodash objectDifference implementation and benchmark code
(function(module) {
var Benchmark = require('../vendor/benchmark.js/benchmark.js'),
_ = require('../vendor/underscore/underscore.js'),
lodash = require('../lodash.js');
var numbers = [],
fourNumbers = [5, 25, 10, 30],
twoNumbers = [12, 21],
i;
for (i = 0; i < 1000; i++) {
numbers.push(Math.round(Math.random() * 10000));
}
for (i = 0; i < 1000; i++) {
fourNumbers.push(Math.round(Math.random() * 10000));
}
for (i = 0; i < 1000; i++) {
twoNumbers.push(Math.round(Math.random() * 10000));
}
function test(numbers, twoNumbers, fourNumbers) {
console.log("array sizes: ", numbers.length, twoNumbers.length, fourNumbers.length);
console.log("lodash is equal to underscore:", JSON.stringify(lodash.difference(numbers, fourNumbers, twoNumbers)) == JSON.stringify(_.difference(numbers, fourNumbers, twoNumbers)));
console.log("lodash is equal to object method:", JSON.stringify(lodash.difference(numbers, fourNumbers, twoNumbers)) == JSON.stringify(lodash.objectDifference(numbers, fourNumbers, twoNumbers)));
console.log("difference size:", lodash.difference(numbers, fourNumbers, twoNumbers).length);
Benchmark.Suite('`_.difference`')
.add('Lo-Dash', function() {
lodash.difference(numbers, fourNumbers, twoNumbers);
})
.add('Underscore', function() {
_.difference(numbers, fourNumbers, twoNumbers);
})
.add('Objects', function() {
lodash.objectDifference(numbers, fourNumbers, twoNumbers);
})
.on('cycle', function(event) {
console.log(String(event.target));
})
.on('complete', function() {
console.log('Fastest is ' + this.filter('fastest').pluck('name'))
}).run({async: false});
}
function testWithSizes(first, second, third, max) {
var numbers = [],
twoNumbers = [],
fourNumbers = [],
i;
for (i = 0; i < first; i++) {
numbers.push(Math.round(Math.random() * max));
}
for (i = 0; i < second; i++) {
twoNumbers.push(Math.round(Math.random() * max));
}
for (i = 0; i < third; i++) {
fourNumbers.push(Math.round(Math.random() * max));
}
test(numbers, twoNumbers, fourNumbers);
}
console.log("=== testing simple ===");
test([], [5, 25, 10, 30], [12, 21]);
console.log("=== testing 10 ===");
testWithSizes(10, 10, 10, 50);
console.log("=== testing 100 ===");
testWithSizes(100, 100, 100, 200);
console.log("=== testing 1k ===");
testWithSizes(1000, 1000, 1000, 10000);
console.log("=== testing 10k ===");
testWithSizes(10000, 10000, 10000, 10000);
console.log("=== testing 100k ===");
testWithSizes(100000, 100000, 100000, 300000);
})(module);
# to be used as lodash method
function objectDifference(array) {
var result = [];
if (!array) {
return result;
}
var index = -1,
length = array.length,
flattened = concat.apply(result, Array.prototype.slice.call(arguments, 1)),
obj = {};
forEach(flattened, function(value, index) {
obj[value] = value;
});
while (++index < length) {
if (obj[array[index]] !== array[index]) {
result.push(array[index]);
}
}
return result;
}
@jdalton
Copy link

jdalton commented Jul 11, 2012

this will fail with:

var a = {};
var b = {};
var c = {};

_.objectDifference([a, b, c], [b, c, a]); // => should be [], but gets [object, object]

@jdalton
Copy link

jdalton commented Jul 11, 2012

This fixes it

  function objectDifference(array) {
    var result = [];
    if (!array) {
        return result;
    }
    var value,
        flattened = concat.apply(result, arguments),
        arrayLength = array.length,
        index = arrayLength - 1,
        length = flattened.length,
        obj = {};

    while (++index < length) {
      value = flattened[index];
      (obj[value] || (obj[value] = [])).push(value);
    }

    index = -1;
    while (++index < arrayLength) {
      value = array[index];
        if (!obj[value] || indexOf(obj[value], value) < 0) {
            result.push(value);
        }
    }
    return result;
  }

@jdalton
Copy link

jdalton commented Jul 11, 2012

I'll look into this more after the v0.4.0 bump.

@bobrik
Copy link
Author

bobrik commented Jul 11, 2012

Sounds good! I was thinking about that solution too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment