3

I have an array of around 30 objects. Each object has a property called 'registration'. The registration property is what I use to uniquely identify each object. Each object also contains a timestamp (always unique).

Every 30 seconds I download a new instance of these 30 objects from an API. There is a possibility that a new object will be added to the current array. I need to come up with a way of checking if the new object is in the array of old (current) objects. If the objects didn't contain a unique timestamp then this would be very simple but as this varies for every instance this won't work.

What I have so far:

newDownloadedArray = JSON.parse(newDownloadedArray);

for (var i = 0; i < currentArrayObjects.length; i++) {
    for (var j = 0; j < newDownloadedArray.length; j++) {

         /* 
         *  This is where I'm stuck.
         *  I now need to check if newDownloadedArray[j].registration is
         *  the value of any registration property inside the currentArrayObjects
         *  array.
         *
         *  If it is, then I know this is a new object.
         */

    }
}

2 Answers 2

2

Here is one solution:

var isNewObject = function(newObject) {
    return !currentArrayObjects.some(function(currentObject) {
        return newObject.registration == currentObject.registration;
    });
};
var onlyNewObjects = newDownloadedArray.filter(isNewObject);

We're basically saying "For every object in newDownloadedArray, look at every object in currentArrayObjects until you find one that has a matching registration. If you do, that object is included in onlyNewObjects. If you don't, it isn't.

Note that Array.prototype.filter and Array.prototype.some are only available in IE 9+, so you might want to use an equivalent helper method or utility library (like underscore) if you want to support older browsers.

This isn't very efficient. For arrays of 30 items, we're doing work a worst-case of 900 times (if the new array was completely unique, because it has to search through all 30 of the currentArrayObjects for each one of the newDownloadedArray).

But that's not really a lot in browser terms. And you can do a lot to speed it up. For example, instead of searching through the currentArrayObjects in the predicate, we could build an object with all the registrations:

// We want a set of registrations, but JavaScript doesn't
// have a native set class, so we're going to use the keys 
// of an object to simulate sets, because object keys are
// basically sets of strings. Note that this won't work if
// registration isn't a string.
var currentRegistrations = {};
currentArrayObjects.forEach(function(currentObject) {
    // AKA currentRegistrationSet.add(currentObject.registration) if we
    // had an actual set class. I chose 'true' somewhat at random
    // because it felt right; we'll never actually be accessing
    // the value.
    currentRegistrations[currentObject.registration] = true;
});
var isNewObject = function(newObject) {
    // AKA !currentRegistrationSet.contains(newObject.registration) if we
    // had an actual set class.
    return !currentRegistrations.hasOwnProperty(newObject.registration);
}
var onlyNewObjects = newDownloadedArray.filter(isNewObject);

(Same caveat about Array.prototype.forEach)

Now we only have to do about 60 operations -- 30 to build the object ahead of time, and 30 more to check each one.


Your solution wasn't far off from the first one I posted. But you switched the for loops. It could be:

newDownloadedArray = JSON.parse(newDownloadedArray);

var onlyNewObjects = []
for (var i = 0; i < newDownloadedArray.length; i++) {
    var isNewObject = true;
    for (var j = 0; j < currentArrayObjects.length; j++) {
        if (newDownloadedArray[i].registration == currentArrayObjects[j].registration) {
            isNewObject = false;

            break; // no reason to keep looking; we know it isn't new
        }
    }
    if (isNewObject) {
        onlyNewObjects.push(newDownloadedArray[i]);
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer! For the record, I chose to go down the route of storing all registrations in their own array to keep things simple. It does mean having to manage another separate array but I think for speed and organisation purposes it's a great choice for this scenario.
@jskidd3 You should check out the comments I added to the second solution. Storing registrations in an array is not awful, but what you really want is to store the registrations in a set -- searching an an array is O(n); searching a hashset is constant time.
0

If you don't mind using lo-dash.

Here's a fiddle

var newRegistrations = _.difference(
        _.pluck(newDownloadedArray, 'registration')
       , _.pluck(currentArrayObjects, 'registration')
);

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.