2

I have an Array of a few hundred JSON Objects...

var self.collection = [Object, Object, Object, Object, Object, Object…]

Each one looks like this...

0: Object
   id: "25093712"
   name: "John Haberstich"

I'm iterating through the Array searching each Array.id to see if it matches any ids in a second Array...

   var fbContactIDs = ["1072980313", "2502342", "2509374", "2524864", "2531941"] 

   $.each(self.collection, function(index, k) {
        if (fbContactIDs.indexOf(k.id) > -1) {
            self.collection.splice(index, 1);
        };
    });

However this code only works to splice three of the Objects from the self.collection array and then it breaks and gives the following error:

Uncaught TypeError: Cannot read property 'id' of undefined 

The line that is causing the error is this one...

if (fbContactIDs.indexOf(k.id) > -1) {

Could anyone tell me what I'm dong wrong here?

2 Answers 2

5

Because the length of collection will change, the trick is to loop from rear to front

for (var index = self.collection.length - 1; index >= 0; index--) {
    k = self.collection[index];
    if (fbContactIDs.indexOf(k.id) > -1) {
        self.collection.splice(index, 1);
    };
}
Sign up to request clarification or add additional context in comments.

1 Comment

…or to use .splice(index--, 1)
1

You should not change the length of an array while iterating over it.

What you're trying to do is filtering and there's a specific function for that. For example:

[1,2,3,4,5,6,7,8,9,10].filter(function(x){ return (x&1) == 0; })

will return only even numbers.

In your case the solution could then simply be:

self.collection = self.collection.filter(function(k){
    return fbContactIDs.indexOf(k.id) > -1;
});

or, if others are keeping a reference to self.collection and you need to mutate it inplace:

self.collection.splice(0, self.collection.length,
                       self.collection.filter(function(k){
    return fbContactIDs.indexOf(k.id) > -1;
}));

If for some reason you like to process elements one at a time instead of using filter and you need to do this inplace a simple approach is the read-write one:

var wp = 0; // Write ptr
for (var rp=0; rp<L.length; rp++) {
    if (... i want to keep L[x] ...) {
        L[wp++] = L[rp];
    }
}
L.splice(wp);

removing elements from an array one at a time is an O(n**2) operation (because for each element you remove also all the following ones must be slided down a place), the read-write approach is instead O(n).

2 Comments

@thg435: what are the advantages of $.grep(x, f) in respect to x.filter(f)?
I'd use grep for stylistic reasons.

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.