[not sure if this counts as hardcoding] Wherefore art thou

Hi everyone,

I really struggled (or am struggling) with the challenge " Wherefore art thou" and although I eventually solved it, I’m not sure if my solution counts as hardcoding, which is not ideal. I’d be most grateful for any help from the community, thanks in advance.

Link to the challenge: https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/intermediate-algorithm-scripting/wherefore-art-thou

I saw from the “tests” that the second argument had only a maximum of 3 key-value pairs. As such, I came up with a solution that dealt with situations where the second argument had 1 key value pair, or 2 key value pairs, or 3 key value pairs.

I spent a lot of time on this challenge and couldn’t find a way to solve this in such a way so that the code would be “flexible” and allow the second argument to have as many key-value pairs as possible.

I haven’t looked at the answer and I’m not sure whether at this point of the course I really should be able to find a solution that is “flexible”. I’d be most grateful for any feedback on my code and whether this solution is really sub-par. Any hints on how to make it “flexible” would be appreciated too.

Here’s my code:

function whatIsInAName(collection, source) {

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Putting the key value pairs in an array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  let keyValuePairs = [];

  for (const [key, value] of Object.entries(source)) {
    // console.log(`${key}: ${value}`);
    keyValuePairs.push(key);
    keyValuePairs.push(value);
  }
  
  // console.log(keyValuePairs); // eg [ "apple", 1, "cookie", 2 ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Putting all the keys in an array, and all the values in another array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  let keysOnly = [];
  let valuesOnly = [];
  
  // Pushing all the keys into a separate array.
  for (let i = 0; i < keyValuePairs.length; i = i + 2) {
    keysOnly.push(keyValuePairs[i]);
  }

  // Pushing all the values into a separate array.
  for (let i = 1; i < keyValuePairs.length; i = i + 2) {
    valuesOnly.push(keyValuePairs[i]);
  }  

  // console.log(keysOnly);   // eg [ "apple", "cookie" ]
  // console.log(valuesOnly); // eg [ 1, 2 ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Find the number of key-value pairs
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  let numberOfKeyValuePairs = (keyValuePairs.length) / 2

  // console.log(numberOfKeyValuePairs);

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If one key-value pair
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  if (numberOfKeyValuePairs === 1) {
    
    let result = collection.filter((currentValue) => currentValue.hasOwnProperty(keysOnly[0]) && currentValue[keysOnly[0]] === valuesOnly[0])

    console.log(result)  
    return result;
  }

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If two key-value pairs
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  if (numberOfKeyValuePairs === 2) {
    let result = collection.filter((currentValue) => currentValue.hasOwnProperty(keysOnly[0]) && currentValue[keysOnly[0]] === valuesOnly[0] 
      && currentValue.hasOwnProperty(keysOnly[1]) && currentValue[keysOnly[1]] === valuesOnly[1])    

    console.log(result);
    return result;
  }

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // If three key-value pairs
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  if (numberOfKeyValuePairs === 3) {
    let result = collection.filter((currentValue) => currentValue.hasOwnProperty(keysOnly[0]) && currentValue[keysOnly[0]] === valuesOnly[0] 
      && currentValue.hasOwnProperty(keysOnly[1]) && currentValue[keysOnly[1]] === valuesOnly[1]
      && currentValue.hasOwnProperty(keysOnly[2]) && currentValue[keysOnly[2]] === valuesOnly[2])   

    console.log(result);
    return result;
  }

}

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

Thanks again.

1 Like

Ok, two questions

  1. why are you making those arrays instead of using the original data you made the arrays out of

  2. why do you have separate cases for the number of keys

2 Likes

@JeremyLT and @camperextraordinaire, thanks for the comments, appreciate it.

Those are good points, I’ll need to start over again. I made those arrays after trying many different approaches and still couldn’t solve the challenge, so I thought maybe I needed to extract the data and put them into different arrays.

One of the approaches I tried was having a “for” loop, and had two layers (let i = 0…) and (let k = 0) but then the two layers depended on there being 2 key/value pairs. I just couldn’t figure out how to make it so it could accommodate any number of key/value pairs. Also with .filter((currentValue) => ________), it seemed I can test whether a single key/value pair was present, but not whether more than one key/value pair was present at the same time.

I’m not really sure what to do but I think as a starting point I’ll go with using the original data.

Thanks again.

1 Like

I don’t think you need to completely start over. You have code that works. It can be refactored

3 Likes

@JeremyLT, thanks, yeah I’ll try to refactor what I have then :smiley:

2 Likes

Hi @JeremyLT and @camperextraordinaire, I ended up solving this by refactoring what I had. I’ve made the code flexible so that “source” can have many key/value pairs.

I stuck with stripping out the keys and values from “source” into separate arrays first as I couldn’t think of a way to iterate through them if I kept them as part of “source” that’s passed in.

I’ve copied my code below, please feel free to provide feedback if you have time, thanks again for responding to my post earlier.

function whatIsInAName(collection, source) {

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Putting the key value pairs in an array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  let keyValuePairs = [];

  for (const [key, value] of Object.entries(source)) {
    console.log(`${key}: ${value}`);  
    keyValuePairs.push(key);
    keyValuePairs.push(value);
  }
  
  console.log(keyValuePairs); // [ "apple", 1, "bat", 2 ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Putting all the keys in an array, and all the values in another array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  let keysOnly = [];
  let valuesOnly = [];
  
  // Pushing all the keys into a separate array.
  for (let i = 0; i < keyValuePairs.length; i = i + 2) {
    keysOnly.push(keyValuePairs[i]);
  }

  // Pushing all the values into a separate array.
  for (let i = 1; i < keyValuePairs.length; i = i + 2) {
    valuesOnly.push(keyValuePairs[i]);
  }  

  console.log(keysOnly);   // [ "apple", "bat" ]
  console.log(valuesOnly); // [ 1, 2 ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Find the number of key-value pairs
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  let numberOfKeyValuePairs = (keyValuePairs.length) / 2

  console.log(numberOfKeyValuePairs); // 2

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Cloning the array "collection"
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  
  let clonedCollection = collection.slice();

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Testing to see if both keys are found in "collection"
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  for (let i = 0; i < numberOfKeyValuePairs; i++) {
    for (let k = 0; k < collection.length; k++) {
      if (collection[k].hasOwnProperty(keysOnly[i]) === false) {
        delete clonedCollection[k];
      }
    }
  }
  
  console.log(clonedCollection); // Array(4):
  // At index 0: Object { apple: 1, bat: 3 }
  // At index 1: <1 empty slot> (or undefined)
  // At index 2: Object { apple: 1, bat: 2, cookie: 2 }
  // At index 3: <1 empty slot> (or undefined)

  // At this point, the array "clonedCollection" will have some values that
  // are "undefined" (ie those whose values have been deleted in the code 
  // directly above). Here, I push only those that are *not* undefined to a 
  // new array "keysAreFound".
  let keysAreFound = [];

  for (let i = 0; i < clonedCollection.length; i++) {
    if (clonedCollection[i] !== undefined) {
      keysAreFound.push(clonedCollection[i]);
    }
  }
  console.log(keysAreFound); // Array(2):
  // At index 0: Object { apple: 1, bat: 3 }
  // At index 1: Object { apple: 1, bat: 2, cookie: 2 }

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Testing to see if the key/value pairs actually match
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  // result is a cloned list.
  let result = keysAreFound.slice();

  for (let i = 0; i < numberOfKeyValuePairs; i++) {
    for (let k = 0; k < keysAreFound.length; k++)  {
      if (keysAreFound[k][keysOnly[i]] !== valuesOnly[i]) {
        delete result[k];
      }
    }
  }

  console.log(result); // Array(2):
  // At index 0: <1 empty slot> (or undefined)
  // At index 1: Object { apple: 1, bat: 2, cookie: 2 } 

  let finalResult = [];

  // I loop through the array and only push in values that are *not* 
  // undefined.
  for (let i = 0; i < result.length; i++) {
    if (result[i] !== undefined) {
      finalResult.push(result[i])
    }
  }

  console.log(finalResult);
  return finalResult;
 
}

// I've tweaked this slightly from the original in the challenge for testing purposes.
whatIsInAName([{ "apple": 1, "bat": 3 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 });
1 Like

It got longer and more complicated? That’s definitely not the direction you want a refactor to go.

Let’s back up. Can you explain why you need so many intermediate variables?

2 Likes

@JeremyLT, thanks for the comment.

I just realized I didn’t need so many intermediate variables…

I initially thought that deleting an element from an array meant that the element would disappear and that the array would shorten by one. I thought this would mess with the loop and that’s why throughout the code I cloned arrays to avoid this problem.

I later realized the element that is deleted would show <1 empty slot> (or undefined) but still occupy a spot on the array, and as such, the length of the array would stay the same and the loop wouldn’t be affected… but I forgot to remove the intermediate variables.

Actually, I didn’t “forget”, I just didn’t realize I could do away with them. :flushed:

1 Like

You should be able to use a single nested loop to do everything. I’d start with that as your goal and bulid with that in mind.

2 Likes

@JeremyLT, yikes, I’m way off.

Okay, I’ll need to rethink this, thanks for the comment.

1 Like

Hi all,

I’ve tried simplifying the code but can’t seem to manage. I’m really confused why when I try to use one of the parameters (“collection”) as a variable, my browser says “Uncaught TypeError: collection[k] is undefined”.

I’d be most grateful for any help, thanks in advance.

My latest code:

function whatIsInAName(collection, source) {

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Putting the key value pairs in an array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  let keyValuePairs = [];

  for (const [key, value] of Object.entries(source)) {
    console.log(`${key}: ${value}`);
    keyValuePairs.push(key);
    keyValuePairs.push(value);
  }
  
  console.log(keyValuePairs); // [ "apple", 1, "bat", 2 ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Checking whether the key is found in "collection" and if so, whether 
  // the value matches
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  for (let i = 0; i < keyValuePairs.length; i = i + 2) {
    for (let k = 0; k < collection.length; k++) {
      // Not sure why my browser says "Uncaught TypeError: collection[k] is undefined"
      if (collection[k].hasOwnProperty(keyValuePairs[i]) === false || collection[k][keyValuePairs[i]] !== keyValuePairs[i + 1]) {
        delete collection[k];
      }
    }
  }
  
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Pushing all values that AREN'T undefined into "result" array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  let result = [];

  for (let i = 0; i < collection.length; i++) {
    if (collection[i] !== undefined) {
      result.push(collection[i])
    }
  }
  
  return result;
}

whatIsInAName([{ "apple": 1, "bat": 3 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 });

1 Like

I’d delete this.

collection[k] might not exist because you might have deleted it.

2 Likes

@JeremyLT and @camperextraordinaire, thanks for the quick reply, really appreciate it.

I thought I could delete collection[k] directly as that would lead to an empty slot in the array, given that the slot would still exist nonetheless (ie the value of the empty slot would be “undefined” and the length of the array wouldn’t change, meaning it wouldn’t affect the loop).

In any case, I’ve reworked it and have copied the latest code below, and it works! I just tried passing the challenge with it.

function whatIsInAName(collection, source) {

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Putting the key value pairs in an array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  let keyValuePairs = [];

  for (const [key, value] of Object.entries(source)) {
    console.log(`${key}: ${value}`);  
    keyValuePairs.push(key);
    keyValuePairs.push(value);
  }
  
  console.log(keyValuePairs); // [ "apple", 1, "bat", 2 ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Checking whether the key is found in "collection" and if so, whether 
  // the value matches
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  let clonedCollection = collection.slice();

  for (let i = 0; i < keyValuePairs.length; i = i + 2) {
    for (let k = 0; k < collection.length; k++) {
      if (collection[k].hasOwnProperty(keyValuePairs[i]) === false || collection[k][keyValuePairs[i]] !== keyValuePairs[i + 1]) {
        delete clonedCollection[k];
      }
    }
  }

  console.log(clonedCollection);
  
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Pushing all values that AREN'T undefined into "result" array
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

  let result = [];

  for (let i = 0; i < clonedCollection.length; i++) {
    if (clonedCollection[i] !== undefined) {
      result.push(clonedCollection[i])
    }
  }
  
  return result;
}

whatIsInAName([{ "apple": 1, "bat": 3 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], { "apple": 1, "bat": 2 });

Thanks again for all the help. Feel free to comment on the latest code.

1 Like

I’d still remove this.

And this

Really you should need only this, with a bit more complex loop body. Nothing else.

1 Like

@JeremyLT and @camperextraordinaire, thanks again for the help.

@camperextraordinaire, wow, that’s really interesting what you’ve done. I wouldn’t have thought of using a flag and this approach is definitely much more elegant than what I came up with. I might need some time to let this code really sink in.

I might also finally check the answers to see what other ways are possible. Thanks again.

If you look at the solutions, you’ll see something that looks like your loop to create keyValuePairs, but the loop is used directly in checking for the key-value pairs instead of using a loop to make an array that you only loop over.

1 Like

@JeremyLT, thank you, appreciate all the help you’ve given me throughout.

@JeremyLT and @camperextraordinaire, I’ve gone over the solutions provided by fCC and have focused on the first solution provided.

At first the code looked pretty straightforward until I really tried to understand what was happening. I’ve made notes for this solution and was wondering if you could kindly confirm whether my understanding is correct. For anyone else who comes across this post, also feel free to jump in, thanks in advance.

I’ve tweaked the fCC’s solution #1 slightly with “let result” so that I can console log “result” later. I’ve also changed some of the elements in “collection” and “source” slightly so that I can cover different scenarios while I iterate through the loop (to test my understanding).

SPOILER ALERT:

function whatIsInAName(collection, source) {
  // Object.keys() returns an array of an object's keys.
  const sourceKeys = Object.keys(source);

  console.log(sourceKeys); // Array [ "apple", "bat" ]

  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  // Filtering the array "collection"
  // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  let result = collection.filter(obj => {
    for (let i = 0; i < sourceKeys.length; i++) {
      if (!obj.hasOwnProperty(sourceKeys[i]) ||
          obj[sourceKeys[i]] !== source[sourceKeys[i]]) {
        return false;
      }
    }
    return true; // If we're able to reach the end of the "for" loop without
                 // having returned "false", then return "true". 
                 // The filter method adds whatever returns "true" into the 
                 // array "result".
  });

  console.log(result); 
  // Array(1): Object { tennis: 5, apple: 1, bat: 2, cookie: 2 }
  return result;
} 

// Calling the function.
whatIsInAName([{ "tennis": 5, "apple": 1, "bat": 3 }, { "dessert": 6 },
               { "tennis": 5, "apple": 1, "bat": 2, "cookie": 2 }, { "bat":2 }], 
              { "apple": 1, "bat": 2 });

// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// On the first call of the callback:
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// The first time around, "obj" is { "tennis": 5, "apple": 1, "bat": 3 }.

// We then have a "for" loop to iterate through the array "sourceKeys".

// We're saying, if it's *not* the case that "obj" has a key of sourceKeys[i],
// ie "apple", OR obj[apple] is NOT equal to source[apple], then return 
// "false".

// In this case, "obj" *does* have a key of "apple", and obj[apple] (ie 1) is
// equal to source[apple] (ie 1).

// KEY: Since we are *not* returning "false", we go on in the "for" loop,
// this time "i" = 1.

// "obj" is still { "tennis": 5, "apple": 1, "bat": 3 }.

// We're saying, if it's *not* the case that "obj" has a key of sourceKeys[i],
// ie "bat", OR obj[bat] is NOT equal to source[bat], then return 
// "false".

// In this case, "obj" *does* have a key of "bat", but obj[bat] (ie 3) is
// NOT equal to source[bat] (ie 2).

// As such, we return "false", and move on to the next "obj". Everytime we
// return false, we move on to the next "obj" without adding anything to
// the array "result".

// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// On the second call of the callback:
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// The second time around, "obj" is { "dessert": 6 }.

// We're saying, if it's *not* the case that "obj" has a key of sourceKeys[i],
// ie "apple", OR obj[apple] is NOT equal to source[apple], then return 
// "false".

// In this case, "obj" does *not* have a key of "apple", therefore we return
// "false". As such, the "for" loop ends, and we move on to the next "obj".

// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// On the third call of the callback:
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// The third time around, "obj" is 
// { "tennis": 5, "apple": 1, "bat": 2, "cookie": 2 }.

// We're saying, if it's *not* the case that "obj" has a key of sourceKeys[i],
// ie "apple", OR obj[apple] is NOT equal to source[apple], then return 
// "false".

// In this case, "obj" *does* have a key of "apple", and obj[apple] (ie 1) is
// equal to source[apple] (ie 1).

// KEY: Since we are *not* returning "false", we go on in the "for" loop,
// this time "i" = 1.

// "obj" is still { "tennis": 5, "apple": 1, "bat": 2, "cookie": 2 }.

// We're saying, if it's *not* the case that "obj" has a key of sourceKeys[i],
// ie "bat", OR obj[bat] is NOT equal to source[bat], then return 
// "false".

// In this case, "obj" *does* have a key of "bat", AND obj[bat] (ie 2) IS
// equal to source[bat] (ie 2).

// KEY: As such, we do *not* return "false", and the "for" loop has reached 
// the end. If we're able to reach the end of the "for" loop without 
// returning false, then we return true, meaning this "obj" is added to the 
// array "result" before we move on to the next obj, which is { "bat":2 }.

// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// On the fourth call of the callback:
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// The fourth time around, "obj" is { "bat":2 }.

// We're saying, if it's *not* the case that "obj" has a key of sourceKeys[i],
// ie "apple", OR obj[apple] is NOT equal to source[apple], then return 
// "false".

// In this case, "obj" does *not* have a key of "apple", therefore we return
// "false". As such, the "for" loop ends, and that "obj" is not added to
// the array "result".

The reason I’ve written out what I think is happening step-by-step is because I find if I don’t have a crystal clear understanding of what’s going on, I don’t actually end up learning the information.

I understand the comments are really long, but if you have a moment it would really help me out if you could confirm whether I’m understanding this correctly, especially at the key points where I’ve labeled “KEY”.

Lastly I was wondering if there’s any tool I can use to see what is happening in the code line-by-line similar to what I’ve written in the comments.

I use Sublime Text as my code editor and can’t figure out where to go to see this line-by-line info. I also downloaded Visual Studio Code yesterday but can’t seem to find this function either.

Sorry about the length of this post and thanks in advance.

@camperextraordinaire, wow, thank you! I’ve never come across this tool before and while it looks a bit intimidating at first (what’s on the right side), I think the green and red arrows are really helpful, as it shows what’s being executed.

I think my notes are correct. Would you say it’s accurate to say that “return true” is executed if we’re able to reach the end of the “for” loop without returning false? Thanks again.

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.