Users are allowed to search their data by keying Name or City or Code. How can I display matched object on the top of the dropdown list.
Prioritizing Code
here as when user enters JOH
the following obj will be highlighted.
{
name: 'John Cena',
code: 'JOH',
city: 'California'
}
Below code works only if user enters the full name or code or city. The list has over 1000 records.
Trying to match the 3 characters code
first with that of user input or otherwise by name or city.
let userInput = e.currentTarget.value;
const input = userInput.toLowerCase()
const filtered = []
if(userList){
for (const user of userList) {
if (user.code.toLowerCase().indexOf(input) > -1
|| user.city.toLowerCase().indexOf(input) > -1
|| user.name.toLowerCase().indexOf(input) > -1
) {
filtered.push(station)
}
}
}
CodePudding user response:
If you also need some sort of priorization (ie a match in code
counts more than a match in name
) you will need to weigh each match and then sort by weight. Assuming userList
is an array
let results = userList.map(user => {
let weight = 0;
if (user.code.toLowerCase().includes(input)) weight = 900
else if (user.name.toLowerCase().includes(input)) weight = 800
else if (user.city.toLowerCase().includes(input)) weight = 700
return { user, weight };
})
.filter(x => x.weight > 0)
.sort((a,b) => b.weight - a.weight)
.map(x => x.user);
This will return a list of users sorted by the best match (ie match by code
) first. It's not super efficent, as it's traversing the list multiple times, but actually I don't think this will be a real issue at just 1000 elements ...
If you run into performance issues, you could for instance refactor userlist.map(...).filter(...)
into userlist.reduce()
but I leave that up to you ... For understanding the solution, I think map
and filter
are easier to read.