wonder if you could help me understand this a little further; tried to use the debugger and various console logs to see where it's failing but still not entirely sure.
Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching name and value pairs (second argument). Each name and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.
For example, if the first argument is [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], and the second argument is { last: "Capulet" }, then you must return the third object from the array (the first argument), because it contains the name and its value, that was passed on as the second argument.
Below is the code not working on the given function below; it should return the following:
[{ "apple": 1, "bat": 2, "cookie": 2 }]
However, all three objects are returned instead of just the one.
p.s. excuse the variable naming convention
function whatIsInAName(collection, source) {
const arr = [];
collection.filter(function (obj) {
const objKeysInSrc = Object.keys(source);
objKeysInSrc.every(function (keyVal) {
console.log(keyVal);
console.log(obj[keyVal]);
console.log(source[keyVal]);
console.log(obj.hasOwnProperty(keyVal));
if (obj.hasOwnProperty(keyVal) && obj[keyVal] === source[keyVal]) {
console.log("match");
arr.push(obj);
}
});
});
console.log(arr);
return arr;
}
whatIsInAName(
[{ apple: 1, bat: 2 }, { bat: 2 }, { apple: 1, bat: 2, cookie: 2 }],
{ apple: 1, bat: 2 }
);
Now this code below works perfectly fine
function whatIsInAName(collection, source) {
const filtArr = collection
.filter(prop => Object.keys(source)
.every(value => prop
.hasOwnProperty(value) && prop[value] === source[value]));
return filtArr;
}
I'm curious to know what could be wrong here as the given test cases work but others fail.
This given function call works:
whatIsInAName(
[
{ first: "Romeo", last: "Montague" },
{ first: "Mercutio", last: null },
{ first: "Tybalt", last: "Capulet" },
],
{ last: "Capulet" }
);
CodePudding user response:
You are not correctly using array methods:
The callback to
filter
should return whether the current item should be included or not, andfilter
will return a new array that has the included items. So you need:- To
return
something in the callback - Capture the array that is returned by
.filter
.
- To
The callback to
every
should return whether the current item is OK or not, andevery
will return a boolean whether all items are OK or not. So you need:- To
return
something in the callback - Capture the boolean that is returned by
.every
- To
The callback to
every
currently pushes an item toarr
when just one key matches, but:- You should only retain an object when every key of the source object is present, not just one
- Using
arr.push
inside aevery
(orfilter
) callback is an anti-pattern. The idea is that you use whatever these methods return.
The correct solution that you posted, does all these things right.
CodePudding user response:
Thanks for this, was helpful. Managed to get it working
function whatIsInAName(collection, source) {
const newCollection = collection
.filter(function(obj) {
return Object.keys(source)
.every(function(keyVal) {
if (obj.hasOwnProperty(keyVal) && obj[keyVal] === source[keyVal]) {
return obj;
}
})
})
return newCollection;
}