Reputation: 6131
Say I have a list of users with firstName
and lastName
and want to filter those who match either first or last names, or both, or any parts, regardless of whitespace. How would I construct that filter?
The closest I've been able to get is
const userString = (user.firstName + user.lastName + user.email).toLowerCase().replace(/\s/g,'');
return userString.includes(filterValue); // where filter value is the thing to test
So if we're working with users = [John Smith, Adam Applebaum, Steve Wright]
, and I type "jo" or "sm" I correctly get "John Smith", but if I type "josm" I would also want "John Smith", but I can't seem to get that to return.
How can I construct a filter or test to include both first and last names, or any combo therein.
@Nina's answer below worked perfect, but I had to modify a bit for my particular use case, my final implementation was;
private _filter(value: string): User[] {
if (!value || typeof value !== 'string') { return this.users; }
const regexp = new RegExp([...(value.split(" "))].join('.*'), 'i');
return this.users.filter(user => {
const userString = user.firstName + ' ' + user.lastName;
return regexp.test(userString);
});
}
Upvotes: 2
Views: 1806
Reputation: 117
@Nina Scholz
example is great, but actually I would go a bit different way, as regexp s.*m.*i.*t.*h
may give a bit inaccurate results.
e.g.
Searched: sh Results: John Smith
Searched: st Results: John Smith
Searched: ji Results: John Smith
Actually any letter from first name and any from last name, and in this case results are inaccurate.
I would rather go with regexp .*SEARCH_PHRASE.*
or to be more exact .*smi.*
But this is personal opinion :) just wanted to show the differences.
Final form would be some kind of this:
function buildPattern(str) {
const arr = [...str];
// as first item
arr.splice(0, 0, '.*');
// as last item
arr.splice(arr.length, 0, '.*');
return new RegExp(arr.join(''), 'i');
}
function filter(array, string) {
return array.filter(RegExp.prototype.test, buildPattern(string));
}
const array = ['John Smith', 'Adam Applebaum', 'Steve Wright'];
console.log(filter(array, "jo"));
console.log(filter(array, "sm"));
console.log(filter(array, "josm"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1
Reputation: 386650
You could space each character with a joker and test the string.
function filter(array, string) {
return array.filter(RegExp.prototype.test, new RegExp([...string].join('.*'), 'i'));
}
var array = ['John Smith', 'Adam Applebaum', 'Steve Wright'];
console.log(filter(array, "jo"));
console.log(filter(array, "sm"));
console.log(filter(array, "josm"));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 2