Androidicus
Androidicus

Reputation: 1748

Fastest way to filter object by multiple properties

I have an array of objects that I want to filter for a string. So I want to check multiple properties if they contain the filter string (case insensitive).

Here's the array:

[{
  id: "01234", 
  name: "My Object 01234", 
  short_name: "MO01234"
}, ...]

So all of the following filter strings should match that object: 0123, obj, mO01 etc.

Here's what I have right now:

const filterString = this.filterString.toLowerCase();
return myObjects.filter(
  entry => {
    return 
      entry.id.toLowerCase().indexOf(filterString) >= 0 || 
      entry.name.toLowerCase().indexOf(filterString) >= 0 ||    
      entry.short_name.toLowerCase().indexOf(filterString) >= 0;
  }
);

Can you think of a faster/cleaner way to do that?

Upvotes: 0

Views: 163

Answers (3)

Jan Wendland
Jan Wendland

Reputation: 1440

let objects = [{
    id: "01234", 
    name: "My Object 01234", 
    short_name: "MO01234"
},
{
    id: "test", 
    name: "test", 
    short_name: "test"
}];

const filter = (collection, searchFor) => {
    return collection.filter(obj => Object.values(obj).reduce((a,b) => a || String(b).toLowerCase().indexOf(searchFor.toLowerCase()) > -1, false))
}

console.log(filter(objects, "0123"));
console.log(filter(objects, "obj"));
console.log(filter(objects, "mO01"));

You could also extend this function to take a set of columns as parameter to filter on.

Another version using Regex:

const filterRegex = (collection, searchFor) => {
    return collection.filter(obj => Object.values(obj).reduce((a,b) => a || String(b).match(new RegExp(searchFor, 'gi')), false))
}


console.log(filterRegex(objects, "0123"));
console.log(filterRegex(objects, "obj"));
console.log(filterRegex(objects, "mO01"));

Upvotes: 0

ilsotov
ilsotov

Reputation: 162

I don't think that you can do it faster, but cleaner may be something like that

const filterString = this.filterString.toLowerCase();
return myObjects.filter((entry) => {
    return Object.values(entry).some((value) => {
        return value.toLowerCase().includes(filterString)
    })
});

Upvotes: 1

Máté Safranka
Máté Safranka

Reputation: 4106

If you are allowed to put additional properties in your object, perhaps you could concatenate id, name and short_name (already in lowercase) into a single string and store it in the object as e.g. search_key; then you'd only have to check that.

{
  id: "01234", 
  name: "My Object 01234", 
  short_name: "MO01234",
  search_key: "01234:my object 01234:mo01234"
}

return myObjects.filter(
  entry => entry.search_key.indexOf(filterString) >= 0
);

One thing you have to be mindful of in this case is to prevent unintended matches that may arise because e.g. the last few characters of id and the first few characters of name together produce a match. This is why I used a : delimiter here, assuming that's a character that can't appear in an ID or a short name.

Upvotes: 0

Related Questions