I needed to create an algorithm which will (efficiently) take an old array and a new array and give me back the changes between the two (which items added, which removed). It happens to need to be in JavaScript (to run in the browser) but the algorithm's more important than the language.
This is what I came up with: http://jsbin.com/osewu3/13. Can anyone see any problems with that/suggest any improvements?
Thanks!
Code Listing:
function diff(o, n) {
// deal with empty lists
if (o == undefined) o = [];
if (n == undefined) n = [];
// sort both arrays (or this won't work)
o.sort(); n.sort();
// don't compare if either list is empty
if (o.length == 0 || n.length == 0) return {added: n, removed: o};
// declare temporary variables
var op = 0; var np = 0;
var a = []; var r = [];
// compare arrays and add to add or remove lists
while (op < o.length && np < n.length) {
if (o[op] < n[np]) {
// push to diff?
r.push(o[op]);
op++;
}
else if (o[op] > n[np]) {
// push to diff?
a.push(n[np]);
np++;
}
else {
op++;np++;
}
}
// add remaining items
if( np < n.length )
a = a.concat(n.slice(np, n.length));
if( op < o.length )
r = r.concat(o.slice(op, o.length));
return {added: a, removed: r};
}
(I have also posted this as a potential solution to another SO question, here: JavaScript array difference)
The array_diff() function compares the values of two (or more) arrays, and returns the differences. This function compares the values of two (or more) arrays, and return an array that contains the entries from array1 that are not present in array2 or array3, etc.
equals() Method. Java Arrays class provides the equals() method to compare two arrays. It iterates over each value of an array and compares the elements using the equals() method.
I created a speed test between two possible implementations.
Source code:
function diff1 (o, n) {
// deal with empty lists
if (o == undefined) o = [];
if (n == undefined) n = [];
// sort both arrays (or this won't work)
o.sort(); n.sort();
// don't compare if either list is empty
if (o.length == 0 || n.length == 0) return {added: n, removed: o};
// declare temporary variables
var op = 0; var np = 0;
var a = []; var r = [];
// compare arrays and add to add or remove lists
while (op < o.length && np < n.length) {
if (o[op] < n[np]) {
// push to diff?
r.push(o[op]);
op++;
}
else if (o[op] > n[np]) {
// push to diff?
a.push(n[np]);
np++;
}
else {
op++;np++;
}
}
// add remaining items
if( np < n.length )
a = a.concat(n.slice(np, n.length));
if( op < o.length )
r = r.concat(o.slice(op, o.length));
return {added: a, removed: r};
}
function diff2 (o, n) {
// convert array items to object members
var objO = {}, objN = {};
for (var i = 0; i < o.length; i++) {
objO[o[i]] = 1;
}
for (var i = 0; i < n.length; i++) {
objN[n[i]] = 1;
}
var a = []; var r = [];
for (var i in objO) {
if (i in objN) {
delete objN[i];
}
else {
r.push (i);
}
}
for (var i in objN) {
a.push (i);
}
return {added: a, removed: r};
}
var o = [], n = [];
for (var i = 0; i < 300000; i++) {
if (i % 2 == 0) {
o.push (i);
}
if (i % 3 == 0) {
n.push (i);
}
}
var start = new Date ();
diff1 (o, n);
var end1 = new Date ();
diff2 (o, n);
var end2 = new Date ();
alert ((end1 - start) + ", " + (end2 - end1));
The disadvantage of diff2 that the returned arrays (added, removed) are not sorted.
Speed Test:
IE7: diff1: 2578ms, diff2: 1906ms
IE8: diff1: 1953ms, diff2: 1152ms
Firefox: diff1: 254ms, diff2: 527ms
Opera: diff1: 143ms, diff2: 253ms
Safari: diff1: 466ms, diff2: 657ms
Chrome: diff1: 734ms, diff2: 581ms
Conclusion: diff1 is faster in Firefox, Opera and Safari, diff2 is faster in IE and Chrome.
There is no undefined
constant. You should check the type of the variable instead:
if (typeof o === 'undefined') o = [];
As Tim Down showed, the property is actually defined in the standard, but as the standard doesn't define it to be constant, it's unreliable and should not be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With