I need to filter array of objects with the existing filter, for example
const students= [
{
id: 1,
name: "Alan",
subjects: [
{
name: "math",
mark: 5
},
{
name: "poetry",
mark: 4
},
{
name: "physics",
mark: 3
}
]
},
{
id: 2,
name: "Joe",
subjects: [
{
name: "geography",
mark: 5
},
{
name: "music",
mark: 5
},
{
name: "literature",
mark: 3
}
]
},
{
id: 3,
name: "Megan",
subjects: [
{
name: "math",
mark: 4
},
{
name: "physics",
mark: 3
}
]
}
];
const filters = [
{
name: "math",
mark: 5
},
{
name: "physics",
mark: 3
}
];
From students array I need to get Alan and Megan according to existing filters. So if at least one subject from filters with mark exists in students, I need to get that student.
I tried this
const common: any = students.filter((x: any) => {
return filters.indexOf(x.skills) !== -1;
});
console.log(common);
But the common array is empty so it didn't work
CodePudding user response:
Something like this?
const students= [
{
id: 1,
name: "Alan",
subjects: [
{
name: "math",
mark: 5
},
{
name: "poetry",
mark: 4
},
{
name: "physics",
mark: 3
}
]
},
{
id: 2,
name: "Joe",
subjects: [
{
name: "geography",
mark: 5
},
{
name: "music",
mark: 5
},
{
name: "literature",
mark: 3
}
]
},
{
id: 3,
name: "Megan",
subjects: [
{
name: "math",
mark: 4
},
{
name: "physics",
mark: 3
}
]
}
];
const filters = [
{
name: "math",
mark: 5
},
{
name: "physics",
mark: 3
}
];
const results = [];
for (const student of students) {
for (const subject of student.subjects) {
const check = filters.some(filter => {
return filter.name == subject.name && filter.mark == subject.mark;
});
if (check) results.push({name: student.name,subject: subject.name,mark: subject.mark});
}
}
console.log(results);
// Output:
// [
// {
// "name": "Alan",
// "subject": "math",
// "mark": 5
// },
// {
// "name": "Alan",
// "subject": "physics",
// "mark": 3
// },
// {
// "name": "Megan",
// "subject": "physics",
// "mark": 3
// }
// ]
CodePudding user response:
One (kind of silly, but) simple way is to apply a filter()
to the array and then stringify
the subjects and filters for comparison. Because two identical (but separate) objects will never evaluate to equal each other, we can't just compare the object. One common alternative is to loop through each of the objects properties for comparison, but in this specific case it's not needed.
const students = [
{
id: 1,
name: "Alan",
subjects: [
{ name: "math", mark: 5 },
{ name: "poetry", mark: 4 },
{ name: "physics", mark: 3 }
]
},
{
id: 2,
name: "Joe",
subjects: [
{ name: "geography", mark: 5 },
{ name: "music", mark: 5 },
{ name: "literature", mark: 3 }
]
},
{
id: 3,
name: "Megan",
subjects: [
{ name: "math", mark: 4 },
{ name: "physics", mark: 3 }
]
}
],
filters = [
{ name: "math", mark: 5 },
{ name: "physics", mark: 3 }
]
let common = students.filter(s => {
let keep = false
filters.forEach(f => {
if(JSON.stringify(s.subjects).includes(JSON.stringify(f))) keep = true
})
return keep
})
console.log(common)
Is this the best way to do this, probably not. However, given what OP has asked for, this does work and is an interesting way to simplify comparing objects.
CodePudding user response:
You can use Array#filter
and Array#some
methods as follows:
const
students = [ { id: 1, name: "Alan", subjects: [ { name: "math", mark: 5 }, { name: "poetry", mark: 4 }, { name: "physics", mark: 3 } ] }, { id: 2, name: "Joe", subjects: [ { name: "geography", mark: 5 }, { name: "music", mark: 5 }, { name: "literature", mark: 3 } ] }, { id: 3, name: "Megan", subjects: [ { name: "math", mark: 4 }, { name: "physics", mark: 3 } ] } ],
filters = [ { name: "math", mark: 5 }, { name: "physics", mark: 3 } ],
output = students.filter(
({subjects}) => filters.some(
({name,mark}) => subjects.some(
({name:n,mark:m}) => n === name && m === mark
)
)
);
console.log( output );