Reputation: 35194
I would like a function that compares to arrays of javascript strings, and saving the values that didnt match in to a new array. At the moment im using a nested jquery foreach. But i think there are better ways than this?
$.each(imagesInUploadsFolder, function(i, outervalue){
$.each(imagesInDatabaseTable, function(i, innervalue){
if(outervalue == innervalue){
//match in both arrays...
}
});
});
Upvotes: 0
Views: 1676
Reputation: 77400
Whether you use jQuery or for
loops, straight-out comparison will be O(n2), since you'll need to compare each element of one array with every element of another array.
If the objects are comparable, you can sort the items using a suitable comparison function, then loop over the two arrays simultaneously, examining if one element is less than the other. If you're familiar with merge-sort, this is very similar to the merge step. Assuming the comparison function is O(1), sorting is O(nlog(n)), and the merge-like comparison loop is O(n), the total time complexity is O(nlog(n)), where "n" is the length of the larger array.
imagesInUploadsFolder.sort(imgCmp);
imagesInDatabaseTable.sort(imgCmp);
// diff will hold the difference of the arrays
var diff = [];
var i=0, j=0, cmp;
while (i < imagesInUploadsFolder.length && j < imagesInDatabaseTable.length) {
cmp = cmp(imagesInUploadsFolder[i], imagesInDatabaseTable[j]);
if (cmp < 0) {
// up[i] < db[j]
++i;
diff.append(imagesInUploadsFolder[i]);
} else if (cmp > 0) {
// up[i] > db[j]
++j;
diff.append(imagesInDatabaseTable[j]);
} else {
// up[i] == db[j]
++i; ++j;
}
}
// one of the arrays may still have items; if so, loop over it and add the items
if (i < imagesInUploadsFolder.length) {
for (; i < imagesInUploadsFolder.length; ++i) {
diff.append(imagesInUploadsFolder[i]);
}
} else if (j < imagesInDatabaseTable.length)) {
for (; i < imagesInDatabaseTable.length; ++i) {
diff.append(imagesInDatabaseTable[i]);
}
}
// diff now holds items that are in only one of the two arrays.
If you can define a suitable object ID function, you can create an ancillary data structure that holds a set of elements. If accessing object properties is O(f(n)) (for hashes, f ≈ 1; for balanced trees, f = log(n)), then this approach is O(n*f(n)), so it should have no worse complexity than the sort-and-compare approach. Untested and inefficient implementation:
function Set(from) {
this.elements = {};
this.size = 0;
if (from) {
for (var i=0; i < from.length) {
this.add(from[i]);
}
}
}
Set.prototype.each = function(f) {
var eltId;
foreach (eltId in this.elements) {
f(this.elements[eltId], eltId);
}
};
Set.prototype.clone = function() {
var clone = new Set();
this.each(function(obj, id) {
clone.add(obj);
});
return clone;
};
Set.prototype.contains = function(obj) {
return obj.uniqueId() in this.elements;
};
Set.prototype.add = function(obj) {
var objId = obj.uniqueId();
if (! (objId in this.elements)) {
++this.size;
this.elements[objId] = obj;
}
return this;
};
Set.prototype.remove = function(obj) {
var objId = obj.uniqueId();
if (objId in this.elements) {
--this.size;
delete this.elements[objId];
}
return this;
};
Set.prototype.union = function(other) {
other.each(function(elt, id) { this.add(elt); });
return this;
};
Set.prototype.sub = function(other) {
other.each(function (elt, id) {
this.remove(elt);
});
return this;
};
Set.prototype.diff = function(other) {
var mine = this.clone();
mine.sub(other);
var others = other.clone();
others.sub(this);
mine.union(others);
return mine;
};
Set.prototype.toArray = function(obj) {
var arr = [];
this.each(function(elt, id) {
arr.append(elt);
});
return arr;
};
var uploadsSet = new Set(imagesInUploadsFolder),
dbSet = new Set(imagesInDatabaseTable),
imagesInJustOne = uploadsSet.diff(dbSet);
If you want both the union and difference of the arrays, you can define a suitable method on Set
to more efficiently calculate them instead of using Set.diff
and Set.union
separately.
Upvotes: 0
Reputation: 49188
Here's a way using a JSON object and no jQuery, although the $.inArray()
should work fine:
var imagesInUploadsFolder = [
'/path/to/img1.png',
'/path/to/img2.png',
'/path/to/img3.png'
];
var imagesInDatabaseTable = [
'/path/to/img1.jpg',
'/path/to/img2.png',
'/path/to/img4.png'
];
var database_json = JSON.stringify(imagesInDatabaseTable);
for (var i = 0; i < imagesInUploadsFolder.length; i++) {
console.log(imagesInUploadsFolder[i] + ' in ' + database_json);
if (database_json.indexOf(imagesInUploadsFolder[i]) > -1) {
console.log('In database: ' + imagesInUploadsFolder[i]);
} else {
console.log('Not in database: ' + imagesInUploadsFolder[i]);
}
}
EDIT
Actually, the JSON method isn't needed (?):
for (var i = 0; i < imagesInUploadsFolder.length; i++) {
console.log(imagesInUploadsFolder[i] + ' in ' + imagesInDatabaseTable);
if (imagesInDatabaseTable.indexOf(imagesInUploadsFolder[i]) > -1) {
console.log('In database: ' + imagesInUploadsFolder[i]);
} else {
console.log('Not in database: ' + imagesInUploadsFolder[i]);
}
}
Upvotes: 1
Reputation: 185893
How about this:
arr1.forEach( function ( elem ) {
if ( arr2.indexOf( elem ) > -1 ) {
// match...
}
});
where arr1
and arr2
are your two arrays...
(Btw, ES5 shim for IE8, of course...)
Upvotes: 2
Reputation: 668
It is the most easier way i can think of right now :)
$.each(imagesInUploadsFolder, function(i, outervalue){
if($.inArray(imagesInDatabaseTable,outervalue)>-1){
//my operation
}
}
FYI: Actually inArray returns index of innermatch else -1. Just incase you need it.
Upvotes: 1
Reputation: 402
Why not use foreach of pure javascript?
for (var i = 0; i < innervalue.length; i++) {
for (var j = 0; j < outervalue.length; j++){
if (innervalue[i] === outervalue[j])
// match
}
}
Upvotes: 1