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

            });
        });
1
  • You obviously want to use the === operator for the comparison... Commented Dec 18, 2011 at 1:03

5 Answers 5

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

Sign up to request clarification or add additional context in comments.

4 Comments

@JaredFarrish Yes? What is it?
+1, but you'll have to shim both forEach and indexOf, won't you?
I was surprised that indexOf() would work on an array. That's all.
@Adam Yes, if you care about IE8, you have to include ES5-shim... (which is not me btw, hehe... )
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/

8 Comments

Thanks, forgot to mention that i was looking for the missmatches only. A little bit modified :) jsfiddle.net/7nJPW/1
@Johan - You can drop the JSON part, it's unnecessary. See my edit.
@Johan - And this will be better (see the c_uploads): jsfiddle.net/7nJPW/4
@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: github.com/kriskowal/es5-shim
@Johan See my post for a relevant example and implementation of a function that does exactly what you are looking for.
|
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
    }
}

Comments

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.

4 Comments

Why use jQuery, when .forEach() and .indexOf() get the job done... :)
he is already using jquery so why not write everything in jquery style .. :)
And i dont think that this is memory consuming part of his code :)
Not the memory consumption, but the performance (= how fast it executes...)
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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.