Filter with two arguments\parameters - arrays

I have a method that should return a list.
I would like to filter the data by two parameters and not one.
So far I have done the following but that's an unwanted result so I've probably done something wrong
performFilterByRunnerName(
filterByCompetition: string, filterByRunnerName: string
): IRunners[] {
return this.runners
.filter(x => x.runnerName === filterByRunnerName)
.filter(x => x.competitionId === filterByCompetition);
}

use && operator
performFilterByRunnerName(
filterByCompetition: string, filterByRunnerName: string
): IRunners[] {
return this.runners
.filter(x => x.runnerName === filterByRunnerName && x.competitionId === filterByCompetition);
}

Doing two filters in sequence means that
You get a first set of values
In this set, you create a new set of values
If it isn't what you want, you should probably explain what it is that you are expecting.
But to inform you, you have :
OR
.filter(x => x.runnerName === filterByRunnerName || x.competitionId === filterByCompetition);
AND
.filter(x => x.runnerName === filterByRunnerName && x.competitionId === filterByCompetition);
XOR
.filter(x =>
(x.runnerName === filterByRunnerName && !(x.competitionId === filterByCompetition)) ||
(!(x.runnerName === filterByRunnerName) && x.competitionId === filterByCompetition));

It's hard to know exactly what's going on from your post. But I'll give it a go:
You have a function,
That accepts two values,
and returns an array,
that is first filtered by one value,
which is passed along the pipe,
and is then filtered by the other value.
That's not the same as, "I am filtering an array by two values," which implies the two filters are a simple "&&". They're not. I've seen this subtle (though important) difference cause an issue many times.
A very simple way to go about it: you can just do as many comparisons inside of one filter as you want.
performFilterByRunnerName(
filterByCompetition: string, filterByRunnerName: string
): IRunners[] {
return this.runners
.filter(x => ( x.runnerName === filterByRunnerName && x.competitionId === filterByCompetition ) );
}
If your end game is to "get all objects that match these two criteria" this should run predictably.

Related

ternary operator inside of Array.map return first true condition

How can I return the first value that equates to true when mapping through objects in an array.
for instance
results.map((item) => {
return item.type == "x" ?
<iframe
src={item.key}
/> :
null
})
in my particular case if I console.log item.key i get 3 different values which is the correct number of objects that have a type that equal "x" how can i return only the first value that equates to true? something like item[0].key is returning undefined.
Item[0] returns null because you use it inside the array loop. So you check every item and if the item is not an array it will not work. Array.find is better in your use case instead of a map.
I would use:
const firstx = results.find((item) => item.type === 'x');
if (firstx) {
return <iframe src={item.key} />;
} else {
return null;
}

How to access values by key from modified React final form

I was making confirmation when the user tried to close the form by modified and values length > 0.
if (modified) {
return (
Object.keys(modified).filter(
(modifiedItem) => modified[modifiedItem] && values[modifiedItem]?.length > 0,
).length > 0
)
}
Everything is working fine until there are values with an array:
when I try to access by values[answers.0.icon] there is undefined, of course, it should be accessed by values.answers[0].icon, by is it possible to do it when iterating modified keys? Or another way should be appreciated.
Thank you beforehand.
Below screenshots of values:
Modified keys:
I'd suggest to include lodash and use the get function. This will resolve the "path" for you.
For example _.get(values, modifiedItem).
More info can be found at https://lodash.com/docs/4.17.15#get
you could add undefined and null in the if statement, to check if it's true and not undefined and not null before it filter else it will be null or you can put something else.
if (modified && modified !== undefined && modified !== null) {
return (
Object.keys(modified).filter(
(modifiedItem) => modified[modifiedItem] && values[modifiedItem]?.length > 0,
).length > 0
)
}
else {
null
}
You can perhaps check for such situation if its an array and treat it differently.
I agree with solution provided by #Stijn answer, however if you dont wanna carry unnecessary baggage of Lodash you can use below code.
const parseDeep = (obj, path, def) => (() => typeof path === 'string' ?
path.replace(/\[(\d+)]/g,'.$1') : path.join('.'))()
.split('.')
.filter(Boolean)
.every(step => ((obj = obj[step]) !== undefined)) ? obj : def
if (modified) {
return (
Object.keys(modified).filter(
(modifiedItem) =>
Array.isArray(modifiedItem) ?
modified[modifiedItem] && parseDeep(values, modifiedItem, false) : //modify as required
modified[modifiedItem] && values[modifiedItem]?.length > 0,
).length > 0
)
}

Speeding up a very slow Vuetify Filter method

I have a working filter method, however it is very slow. text input is passed into $store, and a function is applied to see if anything in an array is a partial match for the text-input. Essentially I am using a computed function to iterate over to display components.
This is effectively the first thing I've tried. It does work in some capacity, but is unbelievably slow and unoptimized.
<v-flex
v-for="myFolder in folderFilter"
:key="myFolder"
xl2
md4
xs6
justfy-space-around
style="padding-top:50px;"
>
<FolderIcon
:folderName="myFolder.folderName"
:folderDescription="myFolder.folderDescription"
:isReadOnly="myFolder.isReadOnly"
:addImage="myFolder.addImage"
:updateHeader="myFolder.updateHeader"
></FolderIcon>
</v-flex>
computed: {
folderFilter(): Folder[] {
let returnFolder: Folder[] = new Array();
if (
this.$store.state.search === "" ||
this.$store.state.search === null
) {
return this.$store.state.displayArray;
} else {
this.$store.state.displayArray.forEach((element: Folder) => {
if (
element.folderName
.toLowerCase()
.includes(this.$store.state.search.toLowerCase())
) {
returnFolder.push(element);
}
});
}
return returnFolder;
}
},
It does work, however when I add more input it is very laggy to take input.

Compare dates in jsx

I am trying to display events for the same day by comparing dates.
How can I use a conditional statement in my map?
{events && events.length && events.map((event) => <Text>{event.author}
{
(currentDay == date)
? 'same'
: 'different'
}
</Text>)
}
How would be the best way to do this?
You can always use isSame from momentjs
moment(currentDay).isSame(date, 'day')
If you need to do a lot of checks to do in your map, remember you can write it like this as well
events.map((event) => {
const text = // your conditional stuff
// some more code if necessary
return (
<Text>{text}</Text>
)
}

Cannot read property 'toJS' of undefined

I have two arrays. But when one of them is null it gives the following error:
Cannot read property 'toJS' of undefined in that line
Here's the relevant call that triggers the error: {groupsGuney.toJS()}
Here's my declaration of the variables let groupsGuney, groupsKuzey;
And finally here are my two arrays. But when one of them is null it gives the error:
...
if (muso == 1) {
groupsGuney = this.props.groups
.groupBy((group, idx) => idx % maxRows)
.map((ggs, idx) => {
return this.renderGroups(ggs, idx);
}).toList().flatten(true);
}
if (muso == 2) {
groupsKuzey = this.props.groups
.groupBy((group, idx) => idx % maxRows)
.map((ggs, idx) => {
return this.renderGroups(ggs, idx);
}).toList().flatten(true);
}
var result = (
<div>
<div className={classSelector + ' discard-mini-box-area'} >
{ groupsGuney.toJS() }
</div>
<div className={classSelector + ' discard-mini-box-area'} >
{ groupsKuzey.toJS() }
</div>
</div>
);
return result;
}
}
export default DiscardMiniBoxArea;
Instead of doing:
<div>
<div className={classSelector + ' discard-mini-box-area'} >
{groupsGuney.toJS()}
</div>
....
you should do:
<div>
<div className={classSelector + ' discard-mini-box-area'} >
{groupsGuney && groupsGuney.toJS()}
</div>
....
Before calling a function on your object, you need to make sure it's there. If you're uncertain about your object having the function at all times, you will need an additional check, that makes sure toJS is there and that it's a valid function.
If that's the case, update what's inside your container to:
{groupsGuney && typeof groupsGuney.toJS === 'function' && groupsGuney.toJS()}
However, ideally, you would not render at all this specific group if what you would like to render is not there. You should move these checks to before you render your component.
My motivation here is mostly that my call .get of undefined poops itself really hard, and initializing properly all over the place helps, but doesn't catch all edge cases. I just want the data or undefined without any breakage. Specific type checking causes me to do more work later if I want it to make changes.
This looser version solves many more edge cases(most if not all extend type Iterable which has .get, and all data is eventually gotten) than a specific type check does(which usually only saves you when you try to update on the wrong type etc).
/* getValid: Checks for valid ImmutableJS type Iterable
returns valid Iterable, valid Iterable child data, or undefined
Iterable.isIterable(maybeIterable) && maybeIterable.get(['data', key], Map()), becomes
getValid(maybeIterable, ['data', key], Map())
But wait! There's more! As a result:
getValid(maybeIterable) returns the maybeIterable or undefined
and we can still say getValid(maybeIterable, null, Map()) returns the maybeIterable or Map() */
export const getValid = (maybeIterable, path, getInstead) =>
Iterable.isIterable(maybeIterable) && path
? ((typeof path === 'object' && maybeIterable.getIn(path, getInstead)) || maybeIterable.get(path, getInstead))
: Iterable.isIterable(maybeIterable) && maybeIterable || getInstead;
//Here is an untested version that a friend requested. It is slightly easier to grok.
export const getValid = (maybeIterable, path, getInstead) => {
if(valid(maybeIterable)) { // Check if it is valid
if(path) { // Check if it has a key
if(typeof path === 'object') { // Check if it is an 'array'
return maybeIterable.getIn(path, getInstead) // Get your stuff
} else {
maybeIterable.get(path, getInstead) // Get your stuff
}
} else {
return maybeIterable || getInstead; // No key? just return the valid Iterable
}
} else {
return undefined; // Not valid, return undefined, perhaps should return false here
}
}
Just give me what I am asking for or tell me no. Don't explode. I believe underscore does something similar also.

Resources