0

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...
                } 

            });
        });
Surjit Samra
  • 4,614
  • 1
  • 26
  • 36
Johan
  • 35,120
  • 54
  • 178
  • 293

5 Answers5

2

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...)

Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
1

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.

ankur.singh
  • 658
  • 5
  • 11
1

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
    }
}
diofeher
  • 395
  • 3
  • 12
1

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]);
    }
}

http://jsfiddle.net/7nJPW/1/

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]);
    }
}

http://jsfiddle.net/7nJPW/2/

Jared Farrish
  • 48,585
  • 17
  • 95
  • 104
  • Thanks, forgot to mention that i was looking for the missmatches only. A little bit modified :) http://jsfiddle.net/7nJPW/1/ – Johan Dec 18 '11 at 01:09
  • @Johan - You can drop the `JSON` part, it's unnecessary. See my edit. – Jared Farrish Dec 18 '11 at 01:10
  • @Johan - And this will be better (see the `c_uploads`): http://jsfiddle.net/7nJPW/4/ – Jared Farrish Dec 18 '11 at 01:12
  • @Johan - Note that `indexOf()` on arrays is a newer method, and some older browsers may not support it natively (or, for that matter, `JSON.stringify()`. See: https://github.com/kriskowal/es5-shim – Jared Farrish Dec 18 '11 at 01:21
  • @Johan See my post for a relevant example and implementation of a function that does exactly what you are looking for. – Filip Roséen - refp Dec 18 '11 at 01:24
  • My last comment with jsfiddle didnt contain my update, here it is: http://jsfiddle.net/7nJPW/6/ . Regarding the old browsers; I think its only IE7 that has some issues with that. – Johan Dec 18 '11 at 02:09
  • @Johan - If you use the [es5 shim library](https://github.com/kriskowal/es5-shim), it should work there too, if you need it to. – Jared Farrish Dec 18 '11 at 02:13
  • Its ok, thanks anyway. And thank you for your detailed answer :) – Johan Dec 18 '11 at 11:28
0

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.

Community
  • 1
  • 1
outis
  • 75,655
  • 22
  • 151
  • 221