Search an Array by all the properties - javascript

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 input = e.currentTarget.value;
const arr = []
for (const user of List) {
if (user.code.includes(input) > -1) {
arr.push(station)
}
}
}

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.

Related

Searching Array of Objects with two search values

so I am trying to make an app that has two search criterias. The front-end app basically fetches data and you have two search bars to filter out the incoming data.
One search is by name and the other is by school name, the tricky part is that the either of the search also takes into account if there is some value in the other search parameter.
For example, if you search for "California University" and "Bob", you should get only Bobs that go to California University to render on the screen. But it seems like right now my DOM only renders the most recent search Ive made. What is the best way to go about a filter that filters both student name and school name using an event listener (keyup) on the search inputs?
searchByNameInput.addEventListener("keyup", (e) => {
const filterNameArray = studentArray.filter((student) => {
// code here to filter students with this name and render it on DOM
}
}
searchBySchoolName.addEventListener("keyup", (e) => {
//filters students who go to this school and render it on DOM
}
}
Write a single filtering function that checks both inputs, and call it from both event listeners.
function filterStudents() {
const nameFilter = searchByNameInput.value;
const schoolFilter = searchBySchoolName.value;
const filterArray = studentArray.filter(student =>
(nameFilter == '' || student.name.includes(nameFilter) &&
(schoolFilter == '' || student.school.includes(schoolFilter))
}
searchByNameInput.addEventListener("keyup", filterStudents);
searchBySchoolNameInput.addEventListener("keyup", filterStudents);
first filter your object and please try it include() method instead of filter().
as a above example
here filterData is my new filtered object and stu_data is my array.
get all search value from search input.
Example:-
var filterData = stu_data.filter((stu_filter) => {
return (stu_filter.firstname.toLowerCase().includes(filter) ||
stu_filter.lastname.toLowerCase().includes(filter))})
I hope this is help for you!
happy coding :)

How to Add Default Elements to an Array when Requirements Not Met?

I have a code that converts user input to an array then does a fetch request. The rest of the code only works when the array has a quantity (as a string) and a unit (as a string). So for example, it works when I type in "1 whole apple" or "1 oz chicken thigh" but it breaks when it's just "apple". How can I set up a checkpoint to add "1" and "whole" to the beginning of the array when quantity and unit are missing?
const [input, setInput] = useState("")
const foodName = []
const searchArray = []
// This part below separates user input by space then forms an array
const inputArray = input.split(/(\s+)/).filter(e => String(e).trim())
// This part below forms a new array with only the quantity and the unit, or nested arrays if the user inputs more than one item, which obviously breaks if there is no quantity.
const array = inputArray.reduce(
(arrays, value) => (
isFinite(value)
? arrays.push([value])
: arrays[arrays.length - 1].push(value),
arrays
),
[]
)
// This part below combines food name to a single element if it has more than one word i.e. apple pie.
for (var i = 0; i < array.length; i++) {
const foodName = array[i].splice(2).join(' ')
foodArray.push(foodName)
const wholeArray = array[i].concat(foodArray[i])
searchArray.push(wholeArray)
}
Making the fetch request etc.
Thanks in advance!
So I ended up adding an error message since I could not find a solution to this.
if (!isFinite(inputArray[0])) {
setErrorMessage('Be sure to specify quantity and unit!')
return
}
const array = inputArray.reduce(
(arrays, value) => (
isFinite(value)
? arrays.push([value])
: arrays[arrays.length - 1].push(value),
arrays
),
[]
)

How to search for multiple words on a HTML page using JavaScript?

Right now my code is looking for the words 'Cheese' or 'Bread' within a specific webpage, and if it finds either word it should display an alert. However, it only displays the alert if the first word is found (cheese). Any suggestions on how to fix it so that it will successfully look for more than one word?
var array = Array.from(document.getElementsByClassName('wide-content-host'))
.find(el => el.innerText.includes('Cheese', 'Bread'));
if (array){
alert("Word found!")
}
This is an obvious change, but we could put an OR operator inside of the statement to signify both of them, like so:
let array = Array.from(document.getElementsByClassName('wide-content-host'))
.find(el => el.innerText.includes('Cheese') || el.innerText.includes('Bread'));
if (array) alert('Word found!');
You could also do it a more elegant way, like so:
const conditions = ['Cheese', 'Bread'];
const array = Array.from(document.getElementsByClassName('wide-content-host'));
const results = array.find((el) => conditions.some(nEl => el.innerText.includes(nEl)));
if (results) alert('Word found!');
This one works by grabbing the array from the 'wide-content-host' class name, then looping through that array with another loop that is looping through the values of the conditions array. With all of these loops working together, it will check whether or not the elements include the conditions.
** Edit **
In order to make the methods work without case-sensitivity, you would need to make the search cases lowercase e.g. 'cheese' and 'bread', and you would need to make the strings that you are searching through completely lowercase also.
Here are the examples for case-insensitivity:
let array = Array.from(document.getElementsByClassName('wide-content-host'))
.find(el => el.innerText.toLowerCase().includes('Cheese') || el.innerText.toLowerCase().includes('Bread'));
if (array) alert('Word found!');
or
const conditions = ['cheese', 'bread'];
const array = Array.from(document.getElementsByClassName('wide-content-host'));
const results = array.find((el) => conditions.some(nEl => el.innerText.toLowerCase().includes(nEl)));
if (results) alert('Word found!');
This can be done with regular expressions
let elem = document.querySelector("section");
let entries = elem.innerHTML.match(/(cheese)|(bread)/gi);
if (entries.length > 0) {
alert(`Words were found: ${entries}`);
}
<section>
<p>Cheese Bread</p>
<p>cheeSE BREAD</p>
</section>

Filter an array based on another array. (Using React)

The goal is to filter an array based on the slots the user has selected.
For example an array has slots for 7pm-9pm,10pm-12pm and so on.
Now the user selects 7pm-9pm, so now I want to filter the array which have 7ppm-9pm or is the users wants
7pm-9pm and 10pm-11pm so the data should be based on 7pm-9pm and 10pm-11pm
Here is how I store the values
This is the original array
data :[
{
name:"something",
phone:"another",
extraDetails : {
// some more data
slots : [
{item:"6PM-7PM"},
{item:"7PM-8pm}
]
}
},{
// Similarly more array with similar data but somewhere slots might be null
}
]
Now for example we have this array
slots:[{6PM-7PM,9PM-10PM,11PM-12AM}]
Now this should filter all those which includes timeslots of 6PM-7PM,9PM-10PM,11PM-12AM
or if the user selects
slots:[{6PM-7PM}]
We should still get the results that includes 6pm-7pm more or else don't matter.
First, I'd suggest using this for your slots representation for simplicity, but you can alter this approach depending on your actual code:
slots: ['6PM-7PM', '9PM-10PM', '11PM-12PM']
Then you can iterate through your data and use filter:
const querySlots = ['6PM-7PM', '9PM-10PM', '11PM-12PM'];
const matchedPersonsWithSlots = data.filter( (person) => {
let i = 0;
while ( i < person.extraDetails.slots.length ) {
if (querySlots.includes(person.extraDetails.slots[i]) return true;
i += 1;
}
return false;
});
matchedPersonsWithSlots will then have all the people that have a slot that matches one of the slots in your query, because if any of the query slots are in a person's list of slots, then it's included in the result set.
EDIT to include a different use case
If, however, every slot in the query array must be matched, then the filtering has to be done differently, but with even less code.
const matchedPersonsWithAllSlots = data.filter(person =>
querySlots.every((qSlot)=>person.extraDetails.slots.includes(qSlot)));
The above will go through each person in your data, and for each of them, determine whether the person has all of your query slots, and include them in the result list, only if this is true.

filtering two arrays with JavaScript/TypeScript

I want to make a list of checkboxes on a UI that user's can use to toggle and filter a set of data results. The checkboxes can be cumulative so I store them as a string array for now. My code looks something like this.
export interface IMyObjectFromAPI {
status: {
id: number,
description: string,
location: string,
name: string,
imageUrl: string
}
}
var filteredByTerms: string[] = [];
var resultsFromAPI: IMyObjectFromAPI [] = [];
var filteredDataResults: IMyObjectFromAPI[] = [];
I save the return results from the api call into the resultsFromAPI array.
On the UI, I have a group of checkboxes based on countries that is populated with a loop through a countries array. On select of a checkbox, I fire off the following code. Again, the goal here is to add multiple things to the array of terms to filter by (so I want to filter by location + name).
filterDataResults(term: string) {
var indexOfTerm = this.filteredByTerms.indexOf(term);
// if the term is not in an array of terms to filter by, add it
if (indexOfTerm === -1) {
this.filteredByTerms.push(term);
this.filteredDataResults = this.resultsFromAPI.filter(x => x.location ===
this.filteredByTerms.includes(term));
}
else {
this.filteredByTerms.splice(indexOfTerm, 1);
this.filteredDataResults = this.resultsFromAPI.filter(x => x.location ===
this.filteredByTerms.includes(term));
}
}
I don't know if I'm explaining this correctly but I've attached a picture to help. A series of checkboxes on the left, a data set on the right, and the checkboxes can be cumulative (so in the image example, if I select ITContractor and Clinical Psychology, the filter function would look for something in the results returned from the API which statifies both conditions.
It seems like some HOFs and map of filters might help you organize your user determined logic/filtering.
const filters = {
lastHourFilter: (result) => result.postedDate > Date.now() - ms('1 hour'),
last24HoursFilter: (result) => result.postedDate > Date.now() - ms('24 hours'),
...
itContractorFilter: generateSpecialismFilter('IT Contractor'),
clinicalPsychologyFilter: generateSpecialismFilter('Clinical Psychology'),
...
fullTimeFilter: generateJobTypeFilter('Full Time'),
temporaryFilter: generateJobTypeFilter('Temporary')
}
Then you inspect the check boxes and determine which filters you should apply to the results. Something like:
function applyFilters(results) {
Object.keys(filters).forEach((key) => {
if (checkboxes[key].checked) results =
results.filter(filters[key]);
});
return results;
}
Here checkboxes is a map of checkboxes in the DOM indexed by the same keys as your filters.

Categories