Structure of Wherefore Art Thou help

Structure of Wherefore Art Thou help
0

#1

Hi All,

I’m having a hell of a time wrapping my head around this challenge. Originally I was able to come up with something worked, but only when the source argument had one value. So I went back to the drawing board to get this to work for multiple values.

Currently I cannot figure out the structure for how to even compare the values. I’ve had many different iterations of this already, but I feel like this one might be the best I have so far.

function whatIsInAName(collection, source) {
  var arr = [];
  var sourceKeys = Object.keys(source);     
    
    for ( var a = 0; a < collection.length; a++ ) {          
      var loopCollect = collection[a];            

        for ( var b = 0; b < sourceKeys.length; b++ ) {
          var singleSrcKey = sourceKeys[b];          
          
          if ( loopCollect.hasOwnProperty(singleSrcKey) ) {                 
            
              arr.push(loopCollect);                                         

          }               
        }        
    }
      
    return arr;

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

Now I realize I’m not testing against the values, yet. I figured I’d just try to break this down to at least compare the keys first, and then once I had that solved I could sprinkle in a conditional to also compare the values. However, maybe I’m thinking about that wrong as well?

So in the example above, it is returning each of the objects within the collection array, however; it’s doubling up the objects each time it loops through. How do I get it to test each of the keys first before it decides to push that into my arr?

Any help would be greatly appreciated as I’ve been on this challenge for a week now and losing my mind haha.


#2

Try to think in plain English.

Something along those lines:

Does each element in collection have all of key/value pairs of source?

Then slowly build up an algorithm from there.

I know I’m not helping much but it’s important YOU go through all the steps from English to code.


#3

My sticking point is how to have the code setup so that it checks it all first before pushing it into the array.

Right now it looks at each value and then it loads it in each time. So I end up with double or triple the amount of objects I need since it repeats itself.

Somehow I need to tell it ‘hold on’ until all values are met, then load it in, and I don’t have any clue of how to get it to do that :frowning:


#4

I don’t want to spoil things for you but I personally hated this challenge because the initial state of the code editor is totally misleading

 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;
}

Protip: arr isn’t used at all in the solutions listed here https://forum.freecodecamp.com/t/freecodecamp-algorithm-challenge-guide-wherefore-art-thou/16092/15

This challenge is pretty terrible. In fact in my solution I left a code comment saying // HOW DARE YOU FCC WORST CHALLENGE YET! to remember to stay salty lol.


#5

Right.

To “hold on” pushing, imagine a variable ok_to_push set to true for each iteration. If one property is not found, or its value is not the expected one then set ok_to_push to false.
When you’ve checked all properties against the current object and if ok_to_push is true then push.

If you get to that point we’ll see how to optimize.

Have fun!


#6

I’d imagine I would use some kind of if statement to set this up, but I’m still not quite sure.

At what point is it ok to look at the answer? lol I really don’t want to but good lord I just can’t seem to get this!


#7

Ha ha no peaking!!

No worries, you’re not too far away from finding the solution.

Here a bit more code to assist you. Fill in the blanks!

var has_all_properties; // reset it to true after setting loopCollect
for ( var a = 0; a < collection.length; a++ ) {
  var loopCollect = collection[a];
  for ( var b = 0; b < sourceKeys.length; b++ ) {
    var singleSrcKey = sourceKeys[b];
    if (!loopCollect.hasOwnProperty(singleSrcKey) ) {
       // property was not found, set has_all_properties to false
    }
    else {
      // loopCollect has the property, check if its value is correct
      // If it isn't then set has_all_properties to false
    }
  }
  // we have now checked all of loopCollect's properties and their values
  // if has_all_properties is true then push loopCollect to final array
}

#8

Oh man! Thank you soooo much for these hints, that is exactly what I needed!!!

I’ll be honest, it still took me about an hour to figure out the if statement for testing values, but I got it!

function whatIsInAName(collection, source) {
  var arr = [];
  var srcKeys = Object.keys(source);     
    
  for ( var a = 0; a < collection.length; a++ ) {
    var has_all_properties = true;     
    var loopCollect = collection[a];

    for ( var b = 0; b < srcKeys.length; b++ ) {
      var singleSrcKey = srcKeys[b];
      if (!loopCollect.hasOwnProperty(singleSrcKey) ) {
        has_all_properties = false; 
      } else {
        if ( loopCollect[singleSrcKey] !== source[singleSrcKey] ) {
          has_all_properties = false; 
        }
      }
    }

    if ( has_all_properties === true ) {
      arr.push(loopCollect);
    }
    
  }
    
  return arr;

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

Time to move on to the next challenge! Hopefully it doesn’t take as long. The whole ‘trigger’ with having that variable set to true or false was probably my biggest take away in this challenge.

Thanks again!

And @StuffieStephie … I returned arr and got the answer :stuck_out_tongue: :smiley:


#9

Excellent.
Now, before moving on to the next challenge it’s important you look back at your code and see how it can be improved.
It’s an important step IMHO, don’t skip it!

  1. do you really need to continue checking all property/values if one doesn’t pass the checks?

  2. check the code below

if (!loopCollect.hasOwnProperty(singleSrcKey)) {
  has_all_properties = false;
}
else if (loopCollect[singleSrcKey] !== source[singleSrcKey]) {
  has_all_properties = false; 
}

As you can see it’s doing the same thing in different places so you should be able to regroup and change conditions to end up with one if.
Can you see how?


#10
function whatIsInAName(collection, source) {  
  var arr = [];
  var srcKeys = Object.keys(source);
  
  for ( var i = 0; i < collection.length; i ++ ) {
    var meets_criteria = true;
    var loopCollect = collection[i];
    
      for ( var j = 0; j < srcKeys.length; j++ ) {
        var singleSrcKey = srcKeys[j];
        
        if ( !loopCollect.hasOwnProperty(singleSrcKey) || loopCollect[singleSrcKey] !== source[singleSrcKey] ) {
          meets_criteria = false;
        }                   
      }
    if ( meets_criteria === true ) {
      arr.push(loopCollect);
    }
  }
  
  
  return arr;
}

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

:smiley: I wish you could tutor me on all these challenges, this has been extremely helpful. Thanks again!


#11

Well done.

Now, there’s only one thing you need to do. Instead of looping through srcKeys.length and marking meets_criteria = false you could use break:

for ( var j = 0; j < srcKeys.length; j++ ) {
  var singleSrcKey = srcKeys[j];
        
  if ( !loopCollect.hasOwnProperty(singleSrcKey) || loopCollect[singleSrcKey] !== source[singleSrcKey] ) {
    meets_criteria = false;
    break; // exits the current for loop
  }                   
}

It’s a little better because if you have 1000 keys and the first one is not found, then you don’t need to check for the other 999.

And it’s usually good practice to take .length outside of the loop condition which is evaluated at each iteration.
Finally, there’s no need to declare variable at each iteration, move all var statements at the top.

Revised code:

function whatIsInAName(collection, source) {
  var arr = [];
  var srcKeys = Object.keys(source);
  var meets_criteria;
  var loopCollect;
  var singleSrcKey;

  for (var i = 0, cl=collection.length; i < cl; i++) {
    meets_criteria = true;
    loopCollect = collection[i];

    for (var j = 0, jl=srcKeys.length; j < jl; j++) {
      singleSrcKey = srcKeys[j];

      if (!loopCollect.hasOwnProperty(singleSrcKey) || loopCollect[singleSrcKey] !== source[singleSrcKey]) {
        meets_criteria = false;
        break;
      }
    }
    if (meets_criteria) { // === true is not needed
      arr.push(loopCollect);
    }
  }
  return arr;
}

Don’t hesitate to post a topic and then message me for code review.

Have fun!


#12

If anyone is interested in a functional solution to this challenge, take a peek below:

function whatIsInAName(collection, source) {
 return collection.filter( (o)=>Object.keys(source).every( (k)=> o[k]===source[k]));
}

#13

Very sexy solution, every is a nice to know method.


#14

Ah great points! Thanks again!!


#15

One day I’ll get to this level haha!


#16

Hello, after tring for hours, I came up with these code:

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

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

But the answer I got is: [object Object]

Can anyone tell me what went wrong, it looks pretty like sethdcd’s code, but it isn’t working…Preformatted text


#17

I will give you a little help and then hopefully you can figure out the rest.

The following line:

    arr += collection[i];

is not doing what I think you want it to do (add collection[i] to arr). Instead you need to change to:

    arr.push(collection[i]);

#18

Thx! now I need to figure out a way to pass the last two test~


#19

I was struggling through this question and just couldn’t figure the structure out. I knew I was very close, but I was having the same problem as the person who asked this question. I knew generally that I needed to wait to push, but I just couldn’t think of how to do it. This was the key. I know you responded to this months ago, but thanks anyway.


#20