Evan Emolo
Evan Emolo

Reputation: 1670

Comparing a Backbone collection to an array

I have a collection I am trying to compare each model's docId attribute to an array of numbers, to return a filtered collection.

If I was comparing the collection's items to a single id, it would be something like:

Docs = Backbone.Collection.extend({
  model: Doc,
  filter_id: function(docId) {
    filtered = this.filter(function(doc) {
      return doc.get('docId') === docId;
    });
    return new Docs(filtered);
  }
});

docId = 123;
docs = new Docs;
filteredDocs = docs.filter_id(docId);

How can I amend the above if I'm dealing with docIds = [123, 456, 789]?

Upvotes: 1

Views: 650

Answers (2)

greim
greim

Reputation: 9437

Classic algorithms question. Easy O(n*m) solution based on indexOf() which @McGarnagle mentioned in a different answer. This is perfectly okay if these lists are small:

filtered = this.filter(function(doc) {
  return docIds.indexOf(doc.get('docId')) != -1;
});

Slightly more complicated O(n) solution based on a lookup table, which you might need if the lists get big or if this is a hot spot in your code:

var table = {};
docIds.forEach(function(docId){
  table[docId] = true;
});
filtered = this.filter(function(doc) {
  return table[doc.get('docId')];
});

The reason is that indexOf() has to scan the whole array, repeated for each item in the collection. n=the length of the collection, m=the length of the array, hence O(n*m). Whereas accessing a property on an object is generally going to be O(1) for each item in the collection, hence O(1*n) or just O(n).

Caveat is that the second solution takes up more memory since it creates an extra object and populates it. You have to decide the tradeoff.

Upvotes: 1

McGarnagle
McGarnagle

Reputation: 102753

Since it's an array of numbers, you could just use indexOf:

filtered = this.filter(function(doc) {
  return docIds.indexOf(doc.get('docId')) != -1;
});

Upvotes: 2

Related Questions