I have an array of objects that is structured like so
const tools = [
{name:"React", image:"react.svg"},
{name:"Firebase", image:"firebase.svg"},
{name:"CSS", image:"css.svg"},
]
I then have an array of strings.
const arr = ["React", "Firebase"]
How can I check that the 'tools' array includes all of the filters in the 'arr' array?
I think I am supposed to use the array.every() or the array.some() operator, but i am not sure how to implement either one in this case.
I found this function from a duplicate question, but it doesn't exactly fit my use case as the first array is an array of objects.
let checker = (arr, target) => target.every(v => arr.includes(v));
So my assumption is to loop through the 'tools' array and perform the check that way, but that doesn't seem right logic-wise?
If these were 2 straight up arrays of strings I could do a simple includes() operator and be done.
How do I move on from here? I'm considering pulling the individual name properties out of the array into a proxy array, so then it is two arrays of strings, but I feel like that is much less efficient than doing it with some() or every().
Edit: I am not sure I was clear, but I am checking against the 'name' property in the tools array.
Thank you for any guidance.
CodePudding user response:
You can create a Set
from the target array, and then reduce the objects' array (arr
) and remove each found item (name
in this case) from the accumulator. If the size
of the Set is 0
, then all targets were found in the array:
const checker = (cb, arr, target) => !arr.reduce((acc, o) => {
acc.delete(cb(o))
return acc
}, new Set(target)).size
[{"name":"React","image":"react.svg"},{"name":"Firebase","image":"firebase.svg"},{"name":"CSS","image":"css.svg"}]
console.log(checker(o => o.name, tools, ["React", "Firebase"]))
console.log(checker(o => o.name, tools, ["React", "Firebase", "Cats"]))
With TS types (TS Playground):
const checker = <T>(
cb: (o: any) => T,
arr: any[],
target: T[]
): boolean => !arr.reduce((acc: Set<T>, o: any) => {
acc.delete(cb(o))
return acc
}, new Set(target)).size
CodePudding user response:
A very simple solution to this is to use array.prototpye.some() method. It wilkl
const tools = [
{name:"React", image:"react.svg"},
{name:"Firebase", image:"firebase.svg"},
{name:"CSS", image:"css.svg"},
]
const arr = ["React", "Firebase"]
function findCommon(arr1, arr2){
arr1.forEach(obj => {
const key = Object.values(obj)
console.log(key.some(item => arr2.includes(item)))
}
)
}
findCommon(tools, arr);
CodePudding user response:
I think the simplest solution would be to use .some()
:
const tools = [
{name:"React", image:"react.svg"},
{name:"Firebase", image:"firebase.svg"},
{name:"CSS", image:"css.svg"},
];
const arr = ["React", "Firebase"]
const result = arr.every((item) => tools.some((tool) => tool.name === item));
console.log(result); // returns true
CodePudding user response:
I'm considering pulling the individual name properties out of the array into a proxy array, so then it is two arrays of strings, but I feel like that is much less efficient than doing it with
some()
orevery()
.
It's by far the easiest approach.
map
over the tools array and get an array of names. Then check to see if the filter array contains all of them.
const tools = [
{name:'React', image:'react.svg'},
{name:'Firebase', image:'firebase.svg'},
{name:'CSS', image:'css.svg'}
];
const arr = ['React', 'Firebase'];
const arr2 = ['React', 'Firebase', 'Steve'];
const arr3 = ['React', 'Firebase', 'CSS'];
const arr4 = ['Firebase'];
const arr5 = ['Steve'];
function contains(tools, arr) {
const names = tools.map(obj => obj.name);
return arr.every(el => names.includes(el));
}
console.log(contains(tools, arr));
console.log(contains(tools, arr2));
console.log(contains(tools, arr3));
console.log(contains(tools, arr4));
console.log(contains(tools, arr5));