freeCodeCamp Challenge Guide: Wherefore art thou

freeCodeCamp Challenge Guide: Wherefore art thou
0

Wherefore Art Thou


Problem Explanation

Write an algorithm that will take an array for the first argument and return an array with all the objects that matches all the properties and values in the Object passed as second parameter.

Relevant Links


Hints

Hint 1

You may use for loop or the Array.prototype.filter method.

Hint 2

Try to use the Object.prototype.hasOwnProperty method to know if the property name exists in an object (as its own property).

Hint 3

Check equivalence of Object in collection with Object passed as second parameter to whatIsInAName function.


Solutions

Solution 1 (Click to Show/Hide)
function whatIsInAName(collection, source) {
  // "What's in a name? that which we call a rose
  // By any other name would smell as sweet.”
  // -- by William Shakespeare, Romeo and Juliet
  var srcKeys = Object.keys(source);

  // filter the collection
  return collection.filter(function(obj) {
    for (var i = 0; i < srcKeys.length; i++) {
      if (
        !obj.hasOwnProperty(srcKeys[i]) ||
        obj[srcKeys[i]] !== source[srcKeys[i]]
      ) {
        return false;
      }
    }
    return true;
  });
}

// test here
whatIsInAName(
  [
    { first: "Romeo", last: "Montague" },
    { first: "Mercutio", last: null },
    { first: "Tybalt", last: "Capulet" }
  ],
  { last: "Capulet" }
);

#### Code Explanation

*   We filter through the array using `.filter()`.
*   Using a `for loop` we loop through each item in the object.
*   We use a `if statement` to check if the object in the collection doesn't have the key and the property value doesn't match the value in source.
*   We return `false` if the above `if statement` is correct. Otherwise, we return `true`;

#### Relevant Links

*   <a>For Loops</a>
*   <a>Array.prototype.filter()</a>
*   <a href='https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty' target='_blank' rel='nofollow'>Object.hasOwnProperty()</a>

</details>

<details><summary>Solution 2 (Click to Show/Hide)</summary>

```javascript
function whatIsInAName(collection, source) {
  // "What's in a name? that which we call a rose
  // By any other name would smell as sweet.”
  // -- by William Shakespeare, Romeo and Juliet
  var srcKeys = Object.keys(source);

  return collection.filter(function(obj) {
    return srcKeys.every(function(key) {
      return obj.hasOwnProperty(key) && obj[key] === source[key];
    });
  });
}

// test here
whatIsInAName(
  [
    { first: "Romeo", last: "Montague" },
    { first: "Mercutio", last: null },
    { first: "Tybalt", last: "Capulet" }
  ],
  { last: "Capulet" }
);

Code Explanation

  • We filter through the collection using .filter().
  • Next, we return a Boolean value for the .filter() method.
  • Finally, we reduce to Boolean value to be returned for the .every() method.

Relevant Links

Solution 3 (Click to Show/Hide)
function whatIsInAName(collection, source) {
  // "What's in a name? that which we call a rose
  // By any other name would smell as sweet.”
  // -- by William Shakespeare, Romeo and Juliet
  var srcKeys = Object.keys(source);

  // filter the collection
  return collection.filter(function(obj) {
    return srcKeys
      .map(function(key) {
        return obj.hasOwnProperty(key) && obj[key] === source[key];
      })
      .reduce(function(a, b) {
        return a && b;
      });
  });
}

// test here
whatIsInAName(
  [
    { first: "Romeo", last: "Montague" },
    { first: "Mercutio", last: null },
    { first: "Tybalt", last: "Capulet" }
  ],
  { last: "Capulet" }
);

Code Explanation

  • We start by filtering through collection using Array.filter().
  • Next, we map through all keys and return Boolean values based on the check conditions: both the key and its corresponding value must exist within the object we are filtering through.
  • Then we reduce the mapped Boolean values to a single Boolean that indicates whether all srcKeys pass the conditions checked above.
  • This single Boolean will be used to filter through the collection.

Relevant Links

8 Likes

There is a bug in the ‘advanced’ solution above. I made a PR to the old wiki project, but was told to contribute here instead. Would be great if the ‘advanced’ solution could be updated. Details can be found here: https://github.com/FreeCodeCamp/wiki/pull/1246

2 Likes

@sautille is still a ‘new user’, once enough trust/reputation is built to progress to ‘basic user’ people can edit wiki posts.

From memory you just need to read a few posts and interact a little to ‘level up’.

Edit

4 Likes

This is just a basic mechanism to avoid spaming.

1 Like

@sautille: I have updated the changes to match and reflect the pull request you made earlier and the change on the main repository as well.

Thanks for contributing.

1 Like

Great post i apprecialte your efforts!

1 Like

I’ve tried to solve this and gotten 2/4 green marks but gave up and came here to take a peek.

But I only got more confused. The exersize says to only change code between the lines.

 var arr = [];
  // Only change code below this line
  
  
  // Only change code above this line
  return arr;

But all the solutions posted here ignore that.

12 Likes

I also got 2/4 green marks using the code below… I understand why my code doesn’t work but I was wondering if anyone knows if it’s possible to make this approach work (without using the filter() method) considering that the exercise tells us not to change the code between the lines. Cheers!

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  for (var i = 0; i < collection.length; i++) {
    for (var prop in source) {
      if (collection[i].hasOwnProperty(prop) && collection[i][prop] === source[prop]) {
        arr.push(collection[i]);
      }
    }
  }
  // Only change code above this line
  return arr;
}

whatIsInAName([{ "a": 1, "b": 2 }, { "a": 1 }, { "a": 1, "b": 2, "c": 2 }], { "a": 1, "b": 2 });
2 Likes

@jacobworrel I think your code is pushing to arr when only ONE property is matched. However, sometimes the source has more than one, an all must be matched.

Right.I just wonder if there’s any way to make my code work when there is more than one property…

Help! Can anyone tell me why my code removed the "" from the keys in my solution?
Here’s my code:

function whatIsInAName(collection, source) {
	var arr=[];
	var k = Object.getOwnPropertyNames(source); 
	var v = source[k]; // assigns var to value in key value pair

	//loop through array of objects
	 for (var i = 0; i < collection.length; i++) {

		//check each object for matching key
	 	if (collection[i].hasOwnProperty(k)) {
	 		
			if (collection[i][k] == v ) { // if object has a match of key value pair...
				arr.push(collection[i]); // add object to arr
			}
		}
	 }
	return arr;
}

The code passed for the 1st test:

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });

but the 2nd didnt pass (keys aren’t in double quotes).

2nd test:
whatIsInAName([{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }], { "a": 1 })

my function returned this:

[ { a: 1 }, { a: 1 }, { a: 1, b: 2 } ]

instead of this:
[{ "a": 1 }, { "a": 1 }, { "a": 1, "b": 2 }]

Why were my keys changed when I pushed them to arr?

And why do none of the spoiler solutions use the starter code that was there? (where the last line is return arr?)

Is it the answer they were looking for? Probably not, given the replies, but I found a solution that works and just thought I would pass it on. Cheers!

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  
var name,
    key,
    soVal,
    coVal;
for(name in source){
  soVal = source[name];
} 
    var i=0;
      for(i; i< collection.length; i++) {
        var obj = collection[i];
          for(key in obj){
            coVal = obj[key];
            if (coVal == soVal && name == key) {
            arr.push(obj);
            }
          } 
      }
     
  // Only change code above this line
  return arr;
}
5 Likes

FYI, the code above for the advanced solution is corrected, but the repl.it it links to still has the old code.

do we have to use the methods in helpful links?

the filter() method works as well

21 Likes

This solution worked for me and it shares your approach. It passed all the test cases.

function whatIsInAName(collection, source) {
  var arr = [];
for (var keyd in source){
 }for (var key in collection){
     if (source[keyd] === collection[key][keyd]){
          arr.push(collection[key]);}
}return(arr);}
1 Like

I solved this with a comparing the objects.
Here is the code:

function whatIsInAName(collection, source) {
  // What's in a name?  
  return collection
    .filter((obj) => JSON.stringify(Object.assign(JSON.parse(JSON.stringify(obj)), source)) === JSON.stringify(obj));
}

Does comparing the objects works faster or slower relatively to using the loop with comparing properties. (Sry for bad English :slight_smile: )

3 Likes

I solved that with couple for loops, it is not elegant as some above solutions, but it works:

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  
  arr = Array.prototype.slice.call(arguments);
  // Only change code below this line
  
  
  var key = Object.keys(source);
  var returncollection =[];
 
  for (i=0; i<collection.length; i++)
    {     
   for (j=0; j<key.length; j++)
    {
     if (collection[i].length<key.length)
       {
        break; 
       } 
     if (collection[i][key[j]]!==source[key[j]])
       {
        break; 
       }
      if (j==key.length-1)
       {
        returncollection = returncollection.concat(collection[i]);
       }
     }      
    }
    //collection2 = collection2.concat(collection[i]);     
  
  // Only change code above this line Object.keys(collection[i])[j]
  return returncollection;
}
5 Likes

Some really interesting solutions in here.

Here is my solution that turned out pretty close to the basic spoiler. I even ended up using some same variable names by coincidence.

I couldn’t figure out an elegant solution in the if/else statement like the basic solution spoiler does on this line:
if(!obj.hasOwnProperty(srcKeys[i]) || obj[srcKeys[i]] !== source[srcKeys[i]])
but I figured out an interesting way to get my return to be true if the tests were passed.

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line  

  arr = collection.filter(function(obj) {
    var srcKeys = Object.keys(source); 
    var test = 0;
    for (var i = 0; i < srcKeys.length; i++) {
      if (obj.hasOwnProperty(srcKeys[i]) && obj[srcKeys[i]] === source[srcKeys[i]]) {
        test += 1;
      } else {
        test += -1;
      }
    }
    return test === srcKeys.length;
  });
  
  // Only change code above this line
  return arr;
}

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" });
2 Likes