Implement a Matching Object Filter - Implement a Matching Object Filter

In addition to my last reply. I noticed why my program isn’t returning an empty array for test cases. For the majority of the test cases, if the property existed in both objects then the value always matched up. There was no difference. However, in these last two test cases the values are different for the same property name.

function whatIsInAName(objArr, sourceObj) {

  const newArray = []; // Array to be returned

  let elementMatch;




  console.log("Array of Objects:");

  console.log(objArr);

  console.log("\nSource Object:");

  console.log(sourceObj);

  console.log("\n");




  for (const element of objArr) {

    console.log("Current Object from Array:");

    console.log(element);

    console.log("\n");




    objectLoop: for (const prop in sourceObj) {

      elementMatch = false;




      for (const arrProp in element) {

        if (element.hasOwnProperty(prop) === true) {

          if (element[arrProp] === sourceObj[prop]) {

            elementMatch = true;

          }

          // I try to add else { break objectLoop; } here, but it leads to me failing other tests.

        }

        else {

          break objectLoop;

        }

      }

    }




    if (elementMatch === true) {

      if (newArray.includes(element) === false) {

        console.log("Element being added to new array:");

        console.log(element);

        console.log("\n");

        

        newArray.push(element);

      }

    }

  }




  console.log("\n");




  return newArray;

}




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

I realized this was leading to the same issue where the property didn’t match, so it just continued to the next iteration and elementMatch was made true again then the element was pushed to the new array. I fixed this with the else branch where I exit the loop I named, so that this overwrite could be avoided.

As you can see in my code, I added a comment for what I wanted to add. However, when I implemented this else branch for if the values did not match it led to various other test cases failing and it didn’t work as I intended.

So, the logic is if the properties match then check if the values match. If the property doesn’t match then skip that element from the array of objects (each element being an object). If the property matches but the value doesn’t match then I want to apply the same logic. If the values don’t match then skip that element. However, it still pushes that element to the new array and just makes my program fail a bunch of other test cases.

Would continue be useful here?

https://www.w3schools.com/jsref/jsref_continue.asp

1 Like

I added continue and it seems to pass those two test cases that expected an empty array. However, it makes all the other tests fail. So, it just flip flops.

objectLoop: for (const prop in sourceObj) {

      elementMatch = false;




      for (const arrProp in element) {

        if (element.hasOwnProperty(prop) === true) {

          if (element[arrProp] === sourceObj[prop]) {

            elementMatch = true;

          } else {

            continue objectLoop;

          }

          // I try to add else { break objectLoop; } here, but it leads to me failing other tests.

        }

        else {

          break objectLoop;

        }

      }

    }

Console Output:

2. whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) should return [{ first: "Tybalt", last: "Capulet" }].
4. whatIsInAName([{ "apple": 1, "bat": 2 }, { "bat": 2 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "bat": 2 }) should return [{"apple": 1, "bat": 2}, {"apple": 1, "bat": 2, "cookie": 2}].
5. whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }], { "apple": 1, "cookie": 2 }) should return [{"apple": 1, "bat": 2, "cookie": 2}].
6. whatIsInAName([{ "apple": 1, "bat": 2 }, { "apple": 1 }, { "apple": 1, "bat": 2, "cookie": 2 }, { "bat": 2 }], { "apple": 1, "bat": 2 }) should return [{"apple": 1, "bat": 2}, {"apple": 1, "bat": 2, "cookie": 2}]
// tests completed
// console output
Array of Objects:
[ { a: 1, b: 2, c: 3 } ]

Source Object:
{ a: 1, b: 9999, c: 3 }


Current Object from Array:
{ a: 1, b: 2, c: 3 }




[]

I would revert to the other code then. It’s very easy to return an empty array, so that’s a better starting place.

The continue would only work an inner loop, so the named loop might be a better method.

1 Like

Revert to the other code as in the code without the continue statement? Or the commented out code which represented the 1st iteration.

I think this clause is in the wrong place:

 else {
          console.log(element, prop)
          //This never fires
          break objectLoop;
        }

I’ve put two console logs and two comments.

function whatIsInAName(objArr, sourceObj) {

  const newArray = []; // Array to be returned
  let elementMatch;

  for (const element of objArr) {
    
    objectLoop: for (const prop in sourceObj) {
      
      elementMatch = false;

      for (const arrProp in element) {
        if (element.hasOwnProperty(prop) === true) {
          if (element[arrProp] === sourceObj[prop]) {
            console.log(element,prop)
            //we should never reach prop c
            elementMatch = true;
          }

        }

        else {
          console.log(element, prop)
          //This never fires
          break objectLoop;
        }

      }

    }

    if (elementMatch === true) {
      if (newArray.includes(element) === false) {
          newArray.push(element);
      }
    }
  }

 return newArray;
}

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

We should never reach prop c in this test. Once prop b does not match, this object should be rejected, correct?

       else {
          console.log("break")
          //This never fires
          break objectLoop;
        }

This is a better log here. It never fires, so the objectLoop is never broken.

Don’t you need to reset elementMatch to False here?

1 Like

I realized the flaw in logic of the else statement. I was attempting to move on to the next element if the current property’s value didn’t match. The .hasOwnProperty if condition simply checked if it existed, but that didn’t mean that property was currently being parsed over. So, I broke free from the loop before the property that matched could be reached.

An alternative I had taken is the following:

function whatIsInAName(objArr, sourceObj) {

  const newArray = []; // Array to be returned

  let elementMatch;




  console.log("Array of Objects:");

  console.log(objArr);

  console.log("\nSource Object:");

  console.log(sourceObj);

  console.log("\n");




  for (const element of objArr) {

    console.log("Current Object from Array:");

    console.log(element);

    console.log("\n");




    objectLoop: for (const prop in sourceObj) {

      console.log(prop);




      elementMatch = false;




      for (const arrProp in element) {

        if (element.hasOwnProperty(prop) === true) {

          if (element[arrProp] === sourceObj[prop]) {

            elementMatch = true;

          } 

          // I try to add else { break objectLoop; } here, but it leads to me failing other tests.

        }

        else {

          break objectLoop;

        }

      }




      // If the property and it's value from the source object didn't fully match then move to next element

      if (elementMatch === false) {

        break objectLoop;

      } 

    }




    if (elementMatch === true) {

      if (newArray.includes(element) === false) {

        console.log("Element being added to new array:");

        console.log(element);

        console.log("\n");

        

        newArray.push(element);

      }

    }

  }




  console.log("\n");




  return newArray;

}




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

I did attempt to reset elementMatch in that location, but as aforementioned the logic was flawed. Instead, I added the break statement at the end of the objectLoop. If the elementMatchis still false even after parsing every key/value pair from the current element in the objects array then it will move onto the next object element in the objects array instead of moving onto the next property in the source object. This solves the issue of certain properties within the source object being reached when they’re not supposed to.

This actually resolved test case 7, one of the two test cases that expected an empty array. However, the last test case still fails and I am not sure as to why. Every test case passes now except test case 8 (the last test case).

Passed this test case for returning an empty array:

7. whatIsInAName([{"a": 1, "b": 2, "c": 3}], {"a": 1, "b": 9999, "c": 3}) should return [].

Failed this test case for returning an empty array:

8. whatIsInAName([{"a": 1, "b": 2, "c": 3, "d": 9999}], {"a": 1, "b": 9999, "c": 3}) should return [].

1 Like

Getting closer :+1:

The basic problem to me is:

  else {
          console.log("break 1")
          break objectLoop;
        }

      }

      if (elementMatch === false) {
        console.log("break 2")
        break objectLoop;
      } 

break 1 and break 2 never fire

if (element[arrProp] === sourceObj[prop]) {

Why do you have 2 different prop here? arrProp and prop ?

1 Like

Hm, I see. I am trying to work with the debugging statements you’re giving me and seeing the output in the console but this implementation I tried to take leads to various test cases failing. I can’t seem to adjust it to fit the current logic.

As for why there are two different names which represent the properties of the object…I thought there may be issues if they had the same name. Though I’m assuming since you’re asking there is no issue with the name prop being used throughout the program for various for…in loops. For now, I’ll leave it as is since my mind is very jumbled processing the execution of statements.

function whatIsInAName(objArr, sourceObj) {

  const newArray = []; // Array to be returned

  let elementMatch;




  console.log("Array of Objects:");

  console.log(objArr);

  console.log("\nSource Object:");

  console.log(sourceObj);

  console.log("\n");




  for (const element of objArr) {

    console.log("Current Object from Array:");

    console.log(element);

    console.log("\n");




    objectLoop: for (const prop in sourceObj) {

      console.log(prop);




      elementMatch = false;




      for (const arrProp in element) {

        if (element.hasOwnProperty(prop) === true) {

          if (element[arrProp] === sourceObj[prop]) {

            elementMatch = true;

          } else {

            console.log("break 1")

            break objectLoop;

          }

          // I try to add else { break objectLoop; } here, but it leads to me failing other tests.

        }

        else {

          console.log("break 2");

          break objectLoop;

        }

      }




      // If the property and it's value from the source object didn't fully match then move to next element

      /* if (elementMatch === false) {

        break objectLoop;

      } */

    }




    if (elementMatch === true) {

      if (newArray.includes(element) === false) {

        console.log("Element being added to new array:");

        console.log(element);

        console.log("\n");

        

        newArray.push(element);

      }

    }

  }




  console.log("\n");




  return newArray;

}




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

Console Output:

Array of Objects:
[ { first: 'Romeo', last: 'Montague' },
  { first: 'Mercutio', last: null },
  { first: 'Tybalt', last: 'Capulet' } ]

Source Object:
{ last: 'Capulet' }


Current Object from Array:
{ first: 'Romeo', last: 'Montague' }


last
break 1
Current Object from Array:
{ first: 'Mercutio', last: null }


last
break 1
Current Object from Array:
{ first: 'Tybalt', last: 'Capulet' }


last
break 1


[]

It does appear to fire, at least for break 1. You also mentioned the clause is in the wrong place, but I am looking for any alternative places it can be and can’t find a logical place it could go. For break 2it breaks out of the objectLoop and proceeds to the next element of the array of objects which doesn’t allow the other properties of the current element to be scanned over.

As aforementioned, the property could exist but the JS interpreter didn’t get the chance to get to it and the break statement makes it break out of the loop before it can be reached. At least that is how I am seeing things currently, but I may have the wrong perspective.

print arrProp and prop using console.log

1 Like
function whatIsInAName(objArr, sourceObj) {

  const newArray = []; // Array to be returned

  let elementMatch;




  console.log("Array of Objects:");

  console.log(objArr);

  console.log("\nSource Object:");

  console.log(sourceObj);

  console.log("\n");




  for (const element of objArr) {

    console.log("Current Object from Array:");

    console.log(element);

    console.log("\n");




    objectLoop: for (const prop in sourceObj) {

      console.log(prop);




      elementMatch = false;




      for (const arrProp in element) {

        if (element.hasOwnProperty(prop) === true) {

          if (element[arrProp] === sourceObj[prop]) {

            console.log("Properties:");

            console.log(arrProp);

            console.log(prop);

            elementMatch = true;

          } /*else {

            console.log("break 1")

            break objectLoop;

          } */

          // I try to add else { break objectLoop; } here, but it leads to me failing other tests.

        }

        /* else {

          console.log("break 2");

          break objectLoop;

        } */

      }




      // If the property and it's value from the source object didn't fully match then move to next element

      if (elementMatch === false) {

        break objectLoop;

      } 

    }




    if (elementMatch === true) {

      if (newArray.includes(element) === false) {

        console.log("Element being added to new array:");

        console.log(element);

        console.log("\n");

        

        newArray.push(element);

      }

    }

  }




  console.log("\n");




  return newArray;

}




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

Console Output:

Array of Objects:
[ { first: 'Romeo', last: 'Montague' },
  { first: 'Mercutio', last: null },
  { first: 'Tybalt', last: 'Capulet' } ]

Source Object:
{ last: 'Capulet' }


Current Object from Array:
{ first: 'Romeo', last: 'Montague' }


last
Current Object from Array:
{ first: 'Mercutio', last: null }


last
Current Object from Array:
{ first: 'Tybalt', last: 'Capulet' }


last
Properties:
last
last
Element being added to new array:
{ first: 'Tybalt', last: 'Capulet' }




[ { first: 'Tybalt', last: 'Capulet' } ]

So, the two properties appear to be the same.

Oh my god…I finally got it. I can’t post the code because it will be a spoiler but I tinkered around and noticed a flaw for that last test case. I wasn’t checking if the two properties are equal first BEFORE checking if the values are equal. This led to a inconsistency in the last test case where one property had a value of 9999 which was assigned to like ‘a’ where-as 9999 was assigned to property ‘c’ in the source object. The program seemed to pass it instead of keeping elementMatch as false.

Thank you SO much for sticking around and actually guiding me in the right direction. Thank to you everyone else that sees this and put in the effort to help me. I literally could not have done it without yall.

I’m free…I’m finally free…!

1 Like

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