The Challenge:
1 2 3 |
Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching property and value pairs (second argument). Each property 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 property and its value, that was passed on as the second argument. |
The solution should return:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
whatIsInAName([ { first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" } ], {last: "Capulet"}) should return [ { first: "Tybalt", last: "Capulet" } ].whatIsInAName([ { "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 } ], {"a": 1}) should return [ { "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 } ].whatIsInAName([ { "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 } ], { "a": 1, "b": 2 }) should return [ { "a": 1, "b": 2 }, { "a": 1, "b": 2, "c": 2 } ].whatIsInAName([ { "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 } ], { "a": 1, "c": 2 }) should return [ { "a": 1, "b": 2, "c": 2 } ] |
Some helpful links:
Object.prototype.hasOwnProperty()
Enumerability and Ownership of Properties
Starter Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
function whatIsInAName(collection, source) { // What's in a name? var arr = []; // Only change code below this line // Only change code above this line return arr; } whatIsInAName([ { first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" } ], {last: "Capulet"}); |
What my solution should achieve:
- Should create a function that checks which object in the first (collection) argument consisting of an array of objects has a key value pair which the second argument does not have, but the key value pairs that ARE present in the second argument are also present in the first.
- Return the object from the first argument that contains the key value pair that is present in the second argument PLUS the key value pair that should be present in the second argument but is only present in the first.
- My function should be able to filter out which object key value pair is present in the first argument and should be present in the second but is not. It should then include that object key value pair in the returned arr. It should also be able to determine which object in the first argument contains the object key value pair that is present in the second argument and include that in returned arr as well.
The helpful links provided hints as to which approach/methods I should take.
First, I knew I was dealing with an array of object literals in the first argument and an object literal in the second.
object literal: a list of zero or more pairs of property names and associated values of an object, enclosed in curly braces ({}
). A property is an association between a name (or key) and a value.
Property names and associated values of an object, aka name value pairs, are also called key value pairs. An object property can refer to the name in the name value pair, or the key in the key value pair. It can also mean the complete name value pair/key value pair.
Example:
1 |
{ first: "Romeo", last: "Montague" } |
Second, I thought that I should create a new variable which stored an empty array that would eventually house the array of object(s) that were to be returned at the end of the function. I called this arr.
Then, based on the helpful links provided and that I was dealing with object literals, I thought that I should use the Object.keys() method.
Object.keys(): returns an array of an object’s non-inherited, non-prototype, enumerable properties, in the same order as a for in loop. Object.keys() returns an array of an object of which the properties directly belong to the object, not inherited through the prototype chain. Because the object’s properties are enumerable, this array of an object can be included in and visited by a for in loop or other similar iteration.
enumerable property: one that can be included in and visited by a for in loop, or a similar iteration of properties, like Object.keys(). If a property isn’t defined as enumerable, the loop will ignore that it is within the object.
Syntax:
1 |
Object.keys(obj) |
Parameters:
obj: the object whose own enumerable properties are to be returned.
Object.keys() is a good method to use here because it works with arrays of objects and their enumerable properties.
Now let’s examine what I had thus far for the solution:
1 2 3 4 5 6 7 8 9 |
function whatIsInAName(collection, source) { var arr = []; var keys = Object.keys(source); return arr; } |
After declaring array arr and assigning the value of an empty array to it, I declared a new variable called keys to which I assigned the value Object.keys(source). I stored the key(s) present in the source argument in the variable keys.
Next I wanted to somehow store the collection argument in another variable, but filter out the objects which did not fit the criteria posed by the algorithm. In other words, filter out the object(s) in collection that don’t contain all the key value pairs present in the source argument, and return those that do contain them, as well as those that are present in collection and should be present in source but are not. So this is what I did next:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
function whatIsInAName(collection, source) { var arr = []; var keys = Object.keys(source); arr = collection.filter(function(obj) { return keys.every(function(key) { return obj.hasOwnProperty(key) && obj[key] === source[key]; }); }); return arr; } |
I reassigned arr by storing collection in its value. Let’s break down what is happening inside the arr variable.
The .filter() method tests the obj parameter inherited from Object.keys(source) against each object in collection, removes the object(s) which don’t share keys present in source, and keys present in source are returned. The keys present in source that are returned are represented by keys.every(). Every source key is checked against each key in collection using the .every() method. Each key in collection is represented by the key parameter in the .every() method callback function. It inherits key from the filtered keys returned from collection.filter(). Next, the .every() method callback function returns the collection key that represents the key missing in source. This is represented by obj.hasOwnProperty(key). obj[key] === source[key] is also returned, and is true because obj === source. Since obj === source, obj[key] === source[key]. [key] refers to the collection key value pair that is strictly equal to source key value pair. Last, arr is returned at the end of the whatIsInAName() function containing the results from
1 |
return obj.hasOwnProperty(key) && obj[key] === source[key]; |
Expected Outcome #1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
whatIsInAName([ { first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" } ], {last: "Capulet"}) should return [ { first: "Tybalt", last: "Capulet" } ] |
In collection, the keys present are first and last. In source, the key present is last. The only shared key value is Capulet. The key missing in source is first, so the object to be returned in arr is { first: “Tybalt”, last: “Capulet” }. Note: the key missing in source refers to both the key (property name) and its associated value Tybalt.
Expected Outcome #2:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
whatIsInAName([ { "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 } ], {"a": 1}) should return [ { "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 } ] |
In collection, the keys present are a and b. In source, the key present is a. The shared key value is 1. The key missing in source is b, so the objects to be returned are { “a”: 1 }, { “a”: 1 }, { “a”: 1, “b”: 2 }.Note: the key missing in source refers to both the key (property name) and its associated value 2.
Expected Outcome #3:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
whatIsInAName([ { "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 } ], { "a": 1, "b": 2 }) should return [ { "a": 1, "b": 2 }, { "a": 1, "b": 2, "c": 2 } ] |
In collection, the keys present are a, b, and c. In source, the keys present are a and b. The shared key values are 1 and 2. The key missing in source is c, so the objects to be returned are { “a”: 1, “b”: 2 }, { “a”: 1, “b”: 2, “c”: 2 }.Note: the key missing in source refers to both the key (property name) and its associated value 2.
Expected Outcome #4:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
whatIsInAName([ { "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 } ], { "a": 1, "c": 2 }) should return [ { "a": 1, "b": 2, "c": 2 } ] |
In collection, the keys present are a, b, and c. In source, the keys present are a and c. The shared key values are 1 and 2. The key missing in source is b, so the object to be returned is { “a”: 1, “b”: 2, “c”: 2 }. Note: the key missing in source refers to both the key (property name) and its associated value 2.
Solution:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
function whatIsInAName(collection, source) { "use strict"; // What's in a name? var arr = []; // Only change code below this line // store keys present in source in variable keys var keys = Object.keys(source); // store collection argument in arr removing objects that don't contain // keys from source. arr = collection.filter(function(obj) { // use arr.every() method to check each collection key against keys from source. return keys.every(function(key) { // return the object(s) in collection that contain the key value pair(s) // missing in source that should be present there as well as the // key value pair(s) that are present in source. return obj.hasOwnProperty(key) && obj[key] === source[key]; }); }); // Only change code above this line return arr; } whatIsInAName([ { first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" } ], {last: "Capulet"}); |
Solution in ES6:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function whatIsInAName(collection, source) { // What's in a name? let arr = []; // Only change code below this line // store keys present in source in variable keys const keys = Object.keys(source); // store collection argument in arr removing objects that don't contain // keys from source. Then // return the object(s) in collection that contain the key value pair(s) // missing in source that should be present there as well as the // key value pair(s) that are present in source. arr = collection.filter(obj => keys.every(key => obj.hasOwnProperty(key) && obj[key] === source[key])); // Only change code above this line return arr; } whatIsInAName([ { first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" } ], {last: "Capulet"}); |
This was first published here on Jul 5, 2016 @ 20:51. It was part of the freecodecamp.org’s **Intermediate JavaScript Algorithm Scripting **for the Front End Development certification.
Comment Policy: Your words are your own, so be nice and helpful if you can. Please, only use your real name and limit the amount of links submitted in your comment. We accept clean XHTML in comments, but don't overdo it please. Comments are moderated, so spammy or malicious links will be removed.