FCC Bonfire Series 116: Where art thou

 

Todays challenge will have us deal with objects; to be more concise, we are going to be working with object properties, or keys. We are tasked with writing a function that takes a list (array) of objects and returns only those that have property values equivalent to the second argument. Sounds confusing but it isn’t, let me show a few examples. I’m going to use a heavily indented syntax so you can get a better look at the objects being used:

where(
  [
    {
      firstname: 'Gorka',
      lastname: 'Hernandez'
    }, {
      firstname: 'John',
      lastname: 'Doe'
    }, {
      firstname: 'Jane',
      lastname: 'Doe'
    }
  ], { lastname: 'Doe' });

// Should return both the John and Jane objects.

where(
  [
    {
      firstname: 'Gorka',
      lastname: 'Hernandez'
    }, {
      firstname: 'John',
      lastname: 'Doe'
    }, {
      firstname: 'Jane',
      lastname: 'Doe'
    }
  ], { firstname: 'John', lastname: 'Doe' });

// Should return only the John object.

where(
  [
    {
      firstname: 'Gorka',
      lastname: 'Hernandez'
    }, {
      firstname: 'John',
      lastname: 'Doe'
    }, {
      firstname: 'Jane',
      lastname: 'Doe'
    }
  ], { age: 23 });

// Returns an empty array.

As you can see, we are returning those objects -inside the first argument array- that match every property in the second argument -an object-. In the first example, both John and Jane share the lastname property with the provided second argument and so, they are returned. The second example also specifies the firstname property, so only John is returned. The last example will return an empty array, since there is no objects in the first argument that have an age property.

Let’s get solving, we know that we should transverse the object array, and test every object within for every property in the second argument. In other words, we are filtering an array based on some criteria. I said filter, and we all know what that means, so let’s get functional!

Here’s a first barebone:

function where(collection, object) {
  return collection.filter(function(currentObj) {
    // Check if every property in the second argument is inside this object.
    // Is is? Return true.
    // It isn't? Return false.
  });
}

There are two ways to go about checking every property inside the objects, using a for…in loop or the Object.keys() method. In this case, I’m going to be using the for…in loop, but you know the drill, try making a version that uses the Object.keys() method yourself!

For the next step, let’s try to give our barebone some working logic, we are going to assume that every object matches the properties defined in the second argument, and return false as soon as one of those does not match, or does not exist. We will be using the aforementioned for…in loop and the Object.prototype.hasOwnProperty() method. The hasOwnProperty method will take a property name as argument, and return true if that property exists within the object it is called on, or false otherwise.

function where(collection, object) {
  return collection.filter(function(currentObj) {
    for (var key in object) {
      if (!currentObj.hasOwnProperty(key) || currentObj[key] !== object[key]) {
        return false;
      }
    }
    return true;
  });
}

Here, inside the filter, we are running the for…in loop that goes over every property inside the second argument object. It then checks if the current object has that property, and if it does, then checks if the values on both current object and second argument are the same. If everything is good and sound, nothing happens, and true is returned at the end. But if any property or property value does not match, false is returned, and that item is filtered out from the array.

Try making the Object.keys() version! This method will return an array containing every existing property inside of the object it is called on.