Wherefore art thou function challenge

Tell us what’s happening:

Your code so far

function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  
  var objLen = collection.length;
  var srk = Object.keys(source);
  var srkLen = srk.length;
  
   for(var i=0;i<objLen;i++){
     
      for(var j=0;j<srkLen;j++){
        
        if(collection[i].hasOwnProperty(srk[j]) && collection[i][srk[j]]==Object.values(source)){
            
            arr.push(collection[i]);

        }
        
      }
     
    }

/*console.log();*/
     
console.log(arr);
  // Only change code above this line
  return arr;
}

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

Your browser information:

Your Browser User Agent is: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36.

Link to the challenge:
https://www.freecodecamp.org/challenges/wherefore-art-thou
I think i’m almost on a verge of discovering how to get around to this challenge. But something is missing. I’m checking for both quantity of keys and value they hold. It should be working, but … isn’t? It works for first two “iterations”, but when function is called and object/second parameter have more then one property, it doesn’t. As it second par … i don’t know … Discards entire first parameter …

Edit1:


function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  
  var objLen = collection.length;
  var srk = Object.keys(source);
  var srkLen = srk.length;
  
   for(var i=0;i<objLen;i++){
     
      for(var j=0;j<srkLen;j++){
        
        if(collection[i].hasOwnProperty(srk[j]) && collection[i][srk[j]]==Object.values(source)[j]){
            
            arr.push(collection[i]);
            
        }
         /*console.log("************************************");*/
        /*console.log(srk[j]+" : "+collection[i][srk[j]]);*/
        /*console.log(srk[j]+" : "+Object.values(source)[j]);*/
        console.log(collection[i][srk[j]]+" : "+Object.values(source)[j]+" "+(collection[i][srk[j]]==Object.values(source)[j]));
      }
     
    }

/*console.log();*/
 

  // Only change code above this line
  /*console.log(arr);*/
  return arr;
}

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

Edit2:


function whatIsInAName(collection, source) {
  // What's in a name?
  var arr = [];
  // Only change code below this line
  var found;
  var objLen = collection.length;
  var srk = Object.keys(source);
  var srkLen = srk.length;
  
   for(var i=0;i<objLen;i++){
     found = true;
      for(var j=0;j<srkLen;j++){
        
        if(!collection[i].hasOwnProperty(srk[j]) || collection[i][srk[j]]!=Object.values(source)[j]){
            found = false;
            
            
        }
        
       if(found == false){
         break;
       }
        
        
         /*console.log("************************************");*/
        /*console.log(srk[j]+" : "+collection[i][srk[j]]);*/
        /*console.log(srk[j]+" : "+Object.values(source)[j]);*/
        /*console.log(collection[i][srk[j]]+" : "+Object.values(source)[j]+" "+(collection[i][srk[j]]==Object.values(source)[j]));*/
      }
     
     if(found == true){
          arr.push(collection[i]);
        }
     
    }

/*console.log();*/
 

  // Only change code above this line
  console.log(arr);
  return arr;
}

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

Remember that Object.keys(source) is an array, so in the third test case (seen below), Object.keys(source) is [‘a’, ‘b’].

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

When you write:

collection[i].hasOwnProperty(Object.keys(source))

then, you are checking if the current collection object has a property named “a,b”. You may ask What? Why? The hasOwnProperty method expects a string, so what ever gets passed to it gets coerced into a string, so when an array such as Objects.keys(source) gets coerced into a string it is just the element values separated by commas. Obviously, you can see why this part of the if condition evaluates to false for the above test case. It was not a problem for the first two test cases, because they only had one property for the source object.

Knowing this now, you can see why the second part of your if condition will also evaluate to false, because collection[i][Object.keys(source)] will evaluate to the value undefined and undefined is not equal to an array.

You are on the right track, but you need to be checking each individual object’s property/values.

I saw it afterward i post it. But forgot to edit post. Can you look at edited post?

I do not see any edits yet.

OK, now I do. Let me review the code.

Basically, it is the same code. You just assigned a reference to the array created by Object.keys(source) to srk and reference srk in the code. While this cleans up the code and makes it more DRY, it still executes as I have described in my first reply.

Doesn’t outer for loop check for that? I saw solution on forum using filter, but it fails to explain it why it works and i’m puzzled since it very similar to mine but without filter method.

The outer loop is just iterating through each element (object) in the collection array.

Let me correct something I said in the previous reply. The first part of your if statement condition is correct, but the second part (seen below) is still an issue.

collection[i][srk[j]]==Object.values(source)

Let me walk you through what the first iteration of the outer for loop and the first two iterations of the inner for loop using the test case of whatIsInAName([{ a: 1, b: 2 }, { a: 1 }, { a: 1, b: 2, c: 2 }], { a: 1, b: 2 }) as an example.

 inside 1st iteration of outer for loop

   i = 0,  collection[0]  = {a: 1, b: 2}
   inside 1st iteration of inner for loop
     j = 0, srk[0] = 'a', so collection[0]['a'] = 1
     collection[0].hasOwnProperty['a') evaluates to true
     collection[0]['a'] == Object.values(source) is comparing 1 to the array [1, 2], so this statement evaluates to false, hence nothing gets pushed into arr.
   end of 1st iteration of inner for loop

   inside 2nd iteration of inner for loop
     j = 1, srk[1] = 'b', so collection[0]['b'] = 2
     collection[0].hasOwnProperty['b') evaluates to true
     collection[0]['b'] == Object.values(source) is comparing 2 to the array [1, 2], so this statement evaluates to false, hence nothing gets pushed into arr.
   end of 1st iteration of inner for loop

end of 1st iteration of outer for loop

So this Object.values(source)[j] should solve(sorta) this issue . I tried putting this console.log(collection[i][srk[j]]+" : “+Object.values(source)[j]+” "+(collection[i][srk[j]]==Object.values(source)[j])); in inner loop(not in if-condition) just to help visualize what is happening and it says in the console:

Montague : Capulet false
null : Capulet false
Capulet : Capulet true
Montague : Capulet false
null : Capulet false
Capulet : Capulet true
Montague : Capulet false
null : Capulet false
Capulet : Capulet true
1 : 1 true
2 : 2 true
1 : 1 true
undefined : 2 false
1 : 1 true
2 : 2 true
1 : 1 true
undefined : 2 false
1 : 1 true
undefined : 2 false
1 : 1 true
2 : 2 true

And Am guessing culprit is hiding on left side in second condition …

My suggestion is to create an extra variable (let’s call it found) which will keep track if all the properties/values of source are found in the collection object during each iteration of the outer for loop. You would need to initialize to the value to true before the start of the inner for loop, which will assume you will find all the properties/values. If either the following two conditions exist:

  1. collection[i] does NOT have a property named srk[j]

OR

  1. collection[i][srk[j]] is NOT equal to source[srk[j]]

then found should be assigned the value of false and then you would need to break out of the inner for loop, because you know this object should not be added. Lastly, right before the end of the outer for loop, you would push the collection object if found is still equal to true.

Ok, i understand it now. Since some(later) calls of function for second parameter could have object with multiple properties and its values and to determine all properties and values, and since this “determination” can’t be done on all properties at same time, so before we evaluate it both, we sort of “pause it” after evaluation of each properties and if all evaluation are “positive”(true), then we “unpause it” i.e set true i.e proceed with pushing it to array. Is this viable explanation? I’m rather new to js objects and English ain’t my native tongue. Long story-short, please look at my Edit2 of the code, it worked following your advice/explanation.