Filter array based on filter combinations - javascript

I have an array as following
array = [
{
name: 'A'
instructors: [
{
name:'InsA'
}
]
businessUnit: {name:'myBusiness'}
},
{
name: 'B'
instructors: [
{
name:'InsB'
}
]
businessUnit: {name:'myBusinessB'}
}
]
I want to filter this array with the values i have which are also in an array as following
classArr = [A,C,D]
instructorArr = [InsA,InsC,InsZ]
businessName = [myBusinessB,myBusinessX,myBusinessD]
NOTE: These filters can have empty arrays as well. For Ex: businessName = [] .
My current approach is to filter as follows
const filtered = array?.filter(
(activity) =>
classArr?.includes(activity.name) &&
activity.instructors?.some((instructor) =>
instructorArr?.some((instructorFilter) => instructor?.name === instructorFilter),
) &&
businessName?.includes(activity.businessUnit?.name),
);
But the issue is this returns if all conditions are met. Not when just 2 or 1 condition is met. How can i return the filtered array when several or all conditions are met?

const filtered = array?.filter(
(activity) =>
classArr?.includes(activity.name) ||
activity.instructors?.some((instructor) =>
instructorArr?.some((instructorFilter) => instructor?.name === instructorFilter),
) ||
businessName?.includes(activity.businessUnit?.name),
);

In your filtered function
const filtered = array?.filter(
(activity) =>
classArr?.includes(activity.name) &&
activity.instructors?.some((instructor) =>
instructorArr?.some((instructorFilter) => instructor?.name === instructorFilter),
) &&
businessName?.includes(activity.businessUnit?.name),
);
You basically say you want to keep all activities where:
The array includes the class name
AND the array includes the instructor
AND the array includes the business unit
(the && operator is the AND operator).
However you state that you want to 'return the filtered array when several [OR] all conditions are met?'
So to fix this, you should switch out the && (AND) operator with the || (OR) operator like this:
const filtered = array?.filter(
(activity) =>
classArr?.includes(activity.name) ||
activity.instructors?.some((instructor) =>
instructorArr?.some((instructorFilter) => instructor?.name === instructorFilter),
) ||
businessName?.includes(activity.businessUnit?.name),
);

You need to check for the length in your array. Only doing array? with check if its nullish, not the size.
const filtered = array?.filter(
(activity) =>
(
classArr.length ? classArr.includes(activity.name) : false
)
&& (
activity.instructors.length // check for length
? activity.instructors.some((instructor) =>
instructorArr.length // check for length
? instructorArr.some((instructorFilter) => instructor.name === instructorFilter)
: false)
: false
)
&& (
businessName.length ? businessName.includes(activity.businessUnit?.name) : false
)
);
That line is very hard to read and will be hard for anyone else to understand in the future, so lets open it up
let filtered = [];
if (array.length){
for (const index in myArray){
const has_classArr = !!classArr.length;
const has_instructorArr = !!instructorArr.length;
const has_businessName = !!businessName.length; // check for length, if you do "businessName?" it only cheks for its existence
if (has_classArr && has_instructorArr && has_businessName){
const activity = myArray[index];
const has_activityInstructors = activity.instructors && activity.instructors.length
const has_activityBusinessUnit = !!activity.businessUnit
if (has_activityInstructors && has_activityBusinessUnit){
for (const instructor of activity.instructors){
if (instructorArr.includes(instructor.name) && businessName.includes(activity.buninessUnit.name) && classArr.includes(activity.name))
filtered.push(activity)
}
}
}
}
}

Related

how to destructure exact values from a unknown array of objects to always go in their specific variables else undefined, but with help of only 1 loop

how to destructure exact values from a unknown array of objects to always go in their specific variables else undefined, but with help of only 1 loop (find ,filter , etc...)
const [tableEdit,tableDelete] = useMemo(() => {
return panelPermissionsPerWidget?.filter(ele => ele.type === 'table_edit' || ele.type ===
'table_delete');
}, [panelPermissionsPerWidget]);
i want index with ele.type===table_edit to only go in tableEdit ,similar with tableDelete
I would pre-populate an array of undefined, loop the list and put into the array 0 & 1 as needed..
eg.
const [tableEdit,tableDelete] = useMemo(() => {
const ret = [undefined, undefined];
if (panelPermissionsPerWidget) {
for (const ele of panelPermissionsPerWidget) {
if (ele.type === 'table_edit') ret[0] = ele
else if (ele.type === 'table_delete') ret[1] = ele;
}
}
return ret;
}, [panelPermissionsPerWidget]);
Instead of array destructor syntax, if you want to destructor different types, then you would be better using object destructoring.
eg.
const {tableEdit,tableDelete} = useMemo(() => {
const ret = {};
if (panelPermissionsPerWidget) {
for (const ele of panelPermissionsPerWidget) {
if (ele.type === 'table_edit') ret.tableEdit = ele
else if (ele.type === 'table_delete') ret.tableDelete = ele;
}
}
return ret;
}, [panelPermissionsPerWidget]);

Change border color of a div conditionally angular

I have these two arrays :
Original Array :
$arr_1=['disappear','rising','filled','decades];
User Array:
$arr_2=['disappear','filled','filled','decade];
this.indexesAttention=[];
$arr_1.forEach(x=>{
//concat two arrays
this.indexesAttention=[...this.indexesAttention,
...this.checkValue(x)]
});
checkValue(variable:string):number[]
{
return this.arr_2
.map((x,index)=>x.trim()==variable.trim()?index:-1)
.filter(x=>x!=-1) //only want the index>>-1
}
These should return the matching indexes in this case it should return [0,2] indexes because they are matching but in my case it is returning 0,2,1,3
[ngStyle]="(indexesAttention.indexOf(i)<0) ? {'border-color':'red','color':'red'} : show_answer === false ? {'border-color': 'black','color':'black'} : {'border-color': 'green','color':'green'}"
Any solution to resolve this issue, Thanks
arr1 = ['disappear','rising','filled','decades'];
arr2 = ['disappear','filled','filled','decade'];
constructor(){
const a = this.arr2.map((e,k) => {
const i = this.arr1.indexOf(e);
return k == i?i:-1;
}).filter(e => e != -1)
const rs = [...new Set(a)]; //output [0, 2]
}

How do I compare two arrays for different message outcomes?

I am trying to compare two arrays( containing 3 integers) and return a hint message array that conform to the logic
-Push “Almost” when 1 digit and position match in array
-push “not quite” when 1 digit matches but different position
-push “incorrect “ when no digits match
push “correct” When exact match
Example of arrays :
Array1 = [2,7,6]
ReferenceArray= [2,9,7]
Hint= [“Almost”, “Not Quite”];
Code I have so far:
function check( array1, referenceArray ) {
let hint=[];
for(i=0;i<referenceArray.length;i++){
for (j=0;j<Array1.length;j++){
//value and position match
if ((referenceArray[i] && reference.indexOf[i]) === (Array1[j] && Array1.indexOf[j])) {
return hint.push('almost');
}
//value matches but not position
else if(( referenceArray[i] ===Array1[j]) && !(referenceArray.indexOf[i]===Array1.indexOf[j] )){
return hint.push('not quite');
}
}// end of Array1 iteration
} // end of reference interation
// if all values and position match
if(referenceArray===Array1){
return hint.push("correct");
}
//if no values match
else if (referenceArray!==Array1){
return hintArray.push("incorrect");
}
I would use some built in Array methods to help achieve this: every(), map() and findIndex().
I generally avoid using .push() because it mutates the array. Immutable code is nice to read 😉
const check = (array, referenceArray) => {
if (array.every((val, index) => val === referenceArray[index] )) {
return ['Correct']
}
const allHints = array.map((val, index) => {
const refArrayIndex = referenceArray.findIndex(refVal => val === refVal);
if (refArrayIndex === index) {
return 'Almost'
}
if (refArrayIndex !== -1) {
return 'Not Quite'
}
return undefined
});
const hints = allHints.filter((hint) => hint !== undefined);
if (hints.length > 0) {
return hints;
}
return ['Incorrect']
};
const hints = check([2,7,6],[2,9,7]);
console.log('hints', hints)
I did this code, tell me if it works or not 😁
const array1 = [2,7,6]
const ReferenceArray = [2,9,7]
function compareArrays(arr){
let perfect = true
for(let i = 0; i < ReferenceArray.length; i++){
if(ReferenceArray[i] != arr[i]) {
perfect = false
break
}
}
if(perfect) return 'correct'
let hint = []
for(let i = 0; i < ReferenceArray.length; i++){
if(arr[i] == ReferenceArray[i]) hint.push('Almost')
else if(ReferenceArray.includes(arr[i])) hint.push('Not Quite')
}
if(hint.length > 0) return hint
return 'incorrect'
}
console.log(compareArrays(array1))

How to get closest previous id from array of object in javascript

I have an array of object,I want to get the closest previous id from nearest object.I can able to get closest next id,its working fine but for previous is not working.Its taking direct first id of object.Here is the code below.Can anyone please help me on it.
JAVASCRIPT
const array = [{id:4}, {id:10}, {id:15}];
const findClosesPrevtId = (x) => ( array.find( ({id}) => x <= id ) || {} ).id;
const findClosestNextId = (x) => ( array.find( ({id}) => x >= id ) || {} ).id;
console.log(findClosesPrevtId(5));
console.log(findClosestNextId(11));
Cause x <= i will be fullfilled for the first element if you use find to search from left to right. Use findLast to search from right to left.
Unfortunately I just found out that there is actually not a findLast yet (there is reduceRight, lastIndexOf ... :/), so you have to write it yourself:
Object.defineProperty(Array.prototype, "findLast", {
value(cb, context) {
for(let i = this.length - 1; i >= 0; i--)
if(cb.call(context, this[i], i, this))
return this[i];
}
});
const findClosesPrevtId = (x) => ( array.findLast( ({id}) => x <= id ) || {} ).id;
You could store the precious/next element and stop the iteration if id is greater than the wanted id.
const
closestPrevious = id => {
var last = {};
array.some(o => o.id > id || (last = o, false))
return last.id;
},
closestNext = id => {
var next = array[0];
array.some((o, i, { [i + 1]: n = {} }) => o.id > id || (next = n, false))
return next.id;
},
array = [{ id: 4 }, { id: 10 }, { id: 15 }];
console.log(closestNext(5)); // 10
console.log(closestNext(11)); // 15
console.log(closestPrevious(5)); // 4
console.log(closestPrevious(11)); // 10
I find it easier to reverse the array and switch the comparison from >= to <=:
const findClosestNextId = (x, arr) =>
(arr.find ( ({id}) => id >= x) || {} ) .id
const findClosestPrevId = (x, arr) =>
(arr .slice(0) .reverse() .find ( ({id}) => id <= x) || {}) .id
const array = [{ id: 4 }, { id: 10 }, { id: 15 }];
console .log (
findClosestNextId (5, array), //=> 10
findClosestNextId (11, array), //=> 15
findClosestNextId (42, array), //=> undefined
findClosestPrevId (5, array), //=> 4
findClosestPrevId (11, array), //=> 10
findClosestPrevId (2, array), //=> undefined
)
The slice call is there to prevent this from modifying the original array. This will return undefined if there is no element found.
I made some changes to your code and it should work now.
Have a look.
const array = [{id:3}, {id:4}, {id:10}, {id:15}];
// you should order the list by id before you try to search, this incase you have not orginized list.
// filter the list first and get the prev id to 5
// you should get 3 and 4 then
// slice(-1) to get the last element of the array which should be 4
const findClosesPrevtId = (x) =>
(array.filter(({id}) => id <= x ).slice(-1)[0] || {}).id;
const findClosestNextId = (x) =>
(array.filter(({id}) => id >= x )[0] || {}).id;
console.log("Prev to 5:"+ findClosesPrevtId(5));
console.log("Next to 11:" +findClosestNextId(11));

Find an Item in an array and add a value

I have two arrays , I want to find the item in Arr1 with Arr2 Keys and map the value of arr2 to arr1 if not found value should be 0.
const Arr1=['A','B','C']
const Arr2=[{key:'a',val:100},{key:'c',val:100}]
Expected Result:
const Arr3=[{key:'a',val:100},{key:'b',val:0},{key:'c',val:100}]
You could use map and find like this:
const Arr1=['A','B','C']
const Arr2=[{key:'a',val:100},{key:'c',val:100}]
const Arr3 = Arr1.map(c => {
const exists = Arr2.find(b => b.key === c.toLowerCase());
return exists || { key: c.toLowerCase(), val: 0 };
})
console.log(Arr3)
Or using reduce like this:
const Arr1=['A','B','C']
const Arr2=[{key:'a',val:100},{key:'c',val:100}]
const Arr3 = Arr1.reduce((r, a) => {
const exists = Arr2.find(b => b.key === a.toLowerCase());
const item = exists || { key: a.toLowerCase(), val: 0 }
return r.concat(item)
},[])
console.log(Arr3)
In context to you previous question you can still return a value if you want and convert keys to lowercase before compare.
const Arr1=['a','b','c']
var Arr2=[{key:'a',val:100},{key:'c',val:100}]
Arr2.map(val => {
if(Arr1.indexOf(val.key) >= 0 )
val.val = val
else
val = 0
})

Categories

Resources