React.js – filter multiple indexOf - javascript

Im just looking for a bit of advice regarding React.js filtering. I am currently filtering ‘peopleList’ by ‘employeeName’ and this is working fine, im getting back exactly what I expect.
But I wanted to also filter by the ‘employeeID’ at the same time i.e. check if ‘employeeName’ or ‘employeeID’ contain an indexOf.. Is this possible or would I need to set up two filters for 'employeeName’ and 'employeeID’?
let people= this.state.peopleList.filter(
(person) => {
return person.record.employeeName.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1;
// return person.record.employeeID.toLowerCase().indexOf(this.state.search.toLowerCase()) !== -1;
}
);

If your condition is either one OR the other, you can use the || operator
const { search, peopleList } = this.state
const searchStr = search.toLowerCase()
const people = peopleList.filter((person) =>
person.record.employeeName.toLowerCase().indexOf(searchStr) !== -1 ||
person.record.employeeId.indexOf(searchStr) !== -1
)

Related

.filter() over array works only the first time

in react-native, I am trying to add a simple filtering option on the top of my screen. Just like this one.
But the filter works only on the first hit. After the first, the new array resolves always as empty.
Could anyone tell me where/why is this code failing? Thanks a lot!
import { exercisesList } from '-utils/exercisesList'
const [items, setItems] = useState(exercisesList)
const handleFilter = (treatment = 'All') => {
console.log('FILTER-TREATMENTE---->', treatment)
let filteredList = exercisesList
if (treatment === 'All') {
setItems(exercisesList)
} else {
filteredList = items.filter((item) => item.treatment === treatment)
console.log('filteredList----->', filteredList)
setItems(filteredList)
}
}
I think it is because the second time that the function runs the items has the previous filteted list, not the full list and you are filtering the items array, not exercistsList
I know others answers solve the problem but I think we can expand on the issue a bit just to better understand what went wrong. It was happening because the filtering was being run directly on the state it was supposed to alter so when second run comes its running on previously filtered data that may or may not meet the filtering requirements. Some pseudo code below on how it should have been done
data -> filter(data) -> updateState(filteredData) -> repeat()
const handleFilter = (treatment = 'All') => {
console.log('FILTER-TREATMENTE---->', treatment);
let filteredList = [];
if (treatment === 'All') {
setItems(exercisesList);
} else {
filteredList = exercisesList.filter((item) => item.treatment === treatment);
console.log('filteredList----->', filteredList);
setItems(filteredList);
}
};

How to filter dynamically instead of using if-else statements

I have a redux hook responsible for server data that I want to pass into a set state after filtering it..
But with a dynamic condition.
// states
const [drilledData, setDrilledData] = useState([])
Current Code:
const drillDownData = (seriesIndex, dataPointIndex) => {
// here series index could be from 1-80 in that order
// dataPointIndex is a number and item.dataSet is also a number
// Refactor this code to remove if-else statements to something better
if (seriesIndex === 0) {
const filteredData = coscoData.filter((item) => item.dataSet === dataPointIndex)
setDrilledData(filteredData[0].shipments)
} else if (seriesIndex === 1) {
const filteredData = hapagData.filter((item) => item.dataSet === dataPointIndex)
setDrilledData(filteredData[0].shipments)
} else if (seriesIndex === 2) {
const filteredData = maerskData.filter((item) => item.dataSet === dataPointIndex)
setDrilledData(filteredData[0].shipments)
} else if (seriesIndex === 3) {
const filteredData = othersData.filter((item) => item.dataSet === dataPointIndex)
setDrilledData(filteredData[0].shipments)
} else {
setDrilledData([])
}
return null
}
Currently, the if-else statement is straightforward and works fine. But I have to repeat that if else statement 80 times. because I have to filter the data and with respect to series index and dataPointIndex and its related dataSet to set them conditionally
like data example
aclData,
admiralLineData,
anlData,
aplData,
arkasData,
data inside them is like that but dataSet can b more than one. so I'm using the filter to pick up matching dataSet to the pointIndex.
aclData = ['dataSet': 1, 'shipments' : [...{more objects}]]
So, I want to make that if else statement dynamic so I don't have to write up to 80 times to cover all the dataSets. How I can do that. ? I don't need to you refactor all code accurately, any idea or pseudo code will also be very helpful.
Is the relationship between the index number and the relevant data set static?
If so, could you create a util object that records those relationships and then use that to dynamically call the data set that you are trying to use? It would be less clunky than a giant if else (or switch statement), and reusable.
If the pattern for the above suggestion is too tricky to implement, a switch statement that calls a helper function, can at least reduce your code:
const filterMyData = (pertinentData, dataIndex) => {
const filteredData = pertinentData.filter((item) => item.dataSet ===
dataIndex)
setDrilledData(filteredData[0].shipments)
}
and then
switch (seriesIndex) {
case 0:
filterMyData(coscoData, dataToPointIndex);
break;
case 1:
filterMyData(hapagData, dataToPointIndex);
break;
....
}

Multiple Filter Methods

I'm trying to solve this problem.
I'm creating a filter method, that has to return me a filtered array based on my preference.
The array is containing some sports bet info, like the odd quote, the starting date, the name of the bookmaker, etc, and I'm trying (for the moment) to just filter based on the min and max odds
First of all, into my "Parent" react component, I receive some info from his child, and those info are stored in an object.
The object is like that:
filters = {minOdd: "", maxOdds:"", ecc...}
And the filter method is like:
setFilters = () => {
const odds = this.state.odds
const filters = this.state.filters
const newOdds = odds.filter((odd) => odd.quota > filters.quotaMin)
.filter((odd) => odd.quota < filters.quotaMax)
}
Where "quota" means "odd", quotaMin means "min odd" and "quotaMax" means max odd
Now, if I set the min and the max odd into my child component, the function returns me an array containing all the right odds. But if I set just one of the 2 filters, this function returns me back an empty object.
I'n my opinion, the problem is that if i don't set one of the 2 value, the filter method compares the odd this a value that is like modd.quota < filters.quotaMax, where filters.quotaMax could be = to "".
Soo i have to not allow the filter method to filter value that are = to "".
If someone can give my an advice!
Thanks in advice!
Use fallback values for the undefined filters.
If either quotaMax or quotaMin is not defined, you are (most likely, haven't seen the structure of a bet) comparing a Number against undefined, which always results in false:
1 < undefined; // -> false
1 > undefined; // -> false
As fallback values, you can use negative and positive infinity. To be honest, it doesn't matter which values you use as long as the fallback for quotaMin is guaranteed to be smaller than the lowest quota and the fallback for quotaMax is guaranteed to be higher than the highest quota.
const newOdds = odds
.filter(odd => odd.quota > (filters.quotaMin || -Infinity))
.filter(odd => odd.quota < (filters.quotaMax || Infinity));
Side note:
You can make your code run faster by merging both predicates into one with AND && (saves one iteraton/filtering).
const newOdds = odds
.filter(odd => odd.quota > (filters.quotaMin || -Infinity) &&
odd.quota < (filters.quotaMax || Infinity));
I guess you just need to handle that case then where quotaMax is undefined/"":
const newOdds = odds.filter((odd) => odd.quota > filters.quotaMin)
.filter((odd) => {
if (filters.quotaMax) {
return odd.quota < filters.quotaMax
} else {
// you decide what should happen in this case..
// return true/false
})

ReactJS / ES6: Searching Japanese text using includes?

So, I'm writing a client-side search and I need to look through strings of Japanese characters. I'm wondering how to do this properly?... i.e. Do I change the format of the text into utf-8 something and then search the utf-8?
Example:
All my data has japaneseData.title : "フェリーチェ三田"
When I type in my search.value as : "フェ" using japaneseData.title.includes(search.value) I don't get a match...
How do I do this correctly?
Okay, after further inspection, the comments were correct and includes was finding the substring. This is all happening inside of a filter() and I'm trying to return the objects that match...
After changing my code to:
let filteredArrayofObjects = Lists.houseLists.filter(house => house.building_name.includes(query.search));
I was getting back some but not all. Problem cases:
"アーバイルスパシエ芝浦BAY-SIDE".includes("エ芝浦"); // this evaluates to true, but does not get included in my filtered array...
Okay, further digging, it seems the issue is I need to wait for the filter process before returning the results... haven't yet found a solution to that just yet.
async filter(arr, callback) {
return (await Promise.all(
arr.map(async item => {
return (await callback(item)) ? item : undefined;
})
)).filter(i => i !== undefined);
}
handleFilterLists = async (query = {}) => {
const { Lists } = this.props;
let searchResults = await this.filter(Lists.houseLists, async house => {
return house.building_name.includes(query.search);
// the final evaluation to look similar to this:
// var newArray = homes.filter(function (el) {
// return el.price <= 1000 &&
// el.sqft >= 500 &&
// el.num_of_beds >=2 &&
// el.num_of_baths >= 2.5;
// });
});
this.setState({ searchResults });
}
Okay, so, I'm trying to set state.searchResults after the filter method has checked for matching objects in the array Lists.houseLists...
includes returns true or false if the substring is detected or not. If you want the index of where the first detected substring begins, use indexOf.
I used your sample source and search text with includes and it returns true.
Edit:
I used your updated data and this still works. https://codepen.io/anon/pen/RMWpwe
const sourceText = 'アーバイルスパシエ芝浦BAY-SIDE';
const searchText = 'エ芝浦';
const lists = [
'スパシエ',
'芝浦BAY-SIDE',
'エ芝浦',
'パシエ芝浦BAY'
];
console.log(lists.filter(item => item.includes(searchText)));
// ["エ芝浦", "パシエ芝浦BAY"]

Dynamically call function with multiple arguments

I'm trying to find similar items amongs a dynamic amount of arrays, For example I might have 2 or 3 arrays with data in them, and want to find the which items exist between all of them.
At the minute i've got this "working" but really ugly code which won't scale past 3 items. The GDAX, PLNX etc are all bools which I have available to tell me whether this option is selected.
The intersectionBy is a lodash helper function with further information available here https://lodash.com/docs/4.17.4#intersectionBy
let similarItems = [];
similarItems = GDAX && PLNX && BTRX ? _.intersectionBy(data.BTRX, data.PLNX, data.GDAX, 'pair') : similarItems;
similarItems = GDAX && PLNX && !BTRX ? _.intersectionBy(data.PLNX, data.GDAX, 'pair') : similarItems;
similarItems = GDAX && !PLNX && BTRX ? _.intersectionBy(data.BTRX, data.GDAX, 'pair') : similarItems;
similarItems = !GDAX && PLNX && BTRX ? _.intersectionBy(data.BTRX, data.PLNX, 'pair') : similarItems;
This should do the job
const input = ['GDAX', 'PLNX', 'BTRX']; // here you pass the strings that are given
const result = _.intersectionBy.apply(_, input.map(name => data[name]).concat(['pair']));
The input could also somehow automized, e.g. giving the object of true / false values for each name, so
const inputObject = { GDAX: true, PLNX: false, BTRX: true };
const names = ['GDAX', 'PLNX', 'BTRX'].filter(name => inputObject[name]);
const result = _.intersectionBy.apply(_, names.map(name => data[name]).concat(['pair']));
For readability and easy maintainability, I'd go with explicitly building a selection according to your boolean flags:
let selection = [];
if (GDAX) selection.push(data.GDAX);
if (PLNX) selection.push(data.PLNX);
if (BTRX) selection.push(data.BTRX);
const result = _.intersectionBy(...selection, 'pair');

Categories