FCC Bonfire Series 145: Inventory Update

Today, we tackle the fourth bonfire within the Advanced Algorithm Scripting section, Inventory Update. The way I’m going to work through this problem is, as always, just one among a sea of possible solutions. With it, I’ll highlight how useful objects can be as opposed to simpler data structures.

Take this with a grain of salt, we are also going to be working with arrays, and we could create a function that works exclusively with these instead. But not today!

Inventory Update will have us write a function that given two 2D arrays (2D array: an array of arrays) containing an inventories. What does this mean? We’ll get two arrays similar to these:

var curInv = [
    [21, "Bowling Ball"],
    [2, "Dirty Sock"],
    [1, "Hair Pin"],
    [5, "Microphone"]
];

var newInv = [
    [2, "Hair Pin"],
    [3, "Half-Eaten Apple"],
    [67, "Bowling Ball"],
    [7, "Toothpaste"]
];

 

The first represents the current inventory, and the second, a fresh delivery. We need to update the quantities on the current inventory to account for the newly received items and, if any item in the new delivery is not present within the original inventory, we add it in alphabetical order. Here’s a very basic example:

var curInv = [
    [5, "Computer Screen"],
    [3, "Keyboard"]
];

var newInv = [
    [2, "Computer Screen"],
    [1, "Orange"]
];

inventory(curInv, newInv); //-> We add 2 Computer screens to the current inventory, and append a single Orange as a new item.
// Result -> [[7, "Computer Screen"], [3, "Keyboard"], [1, "Orange"]]

 

To have this problem be easier, we are going to use objects instead of arrays; but for that, we’ll first create a function that transforms a 2D array into an object. We just need to loop over each item in the array and for each of these, set a new property on an object using the item as property name and setting it to the quantity.

This is what it should do:

var inventoryArray = [
	[4, "Computer Screen"],
	[5, "Apple"],
	[18, "Orange"]
];

createObject(inventoryArray);
// We get the following:
/*
	{
		"Computer Screen": 4,
		"Apple": 5,
		"Orange": 18
	}

*/

 

Let’s get to it then:

function createObject(array) {
	var obj = {};	// We start off by creating an empty object.
	array.forEach(function(current) {	// We loop over the input array.
		obj[current[1]] = current[0];	// We add properties to the object for each item. E.g.: { 'Computer Screen' : 5 }
	});
	return obj;		// We return the object itself.
}

 

Looking good, but the expected output for the function is also an array, and since we’ll be working with an object, we’ll need to create another function that turns an object into a 2D array for the final result. We’ll loop over the object keys, and push a sub-array to the output array for each key value pair that we come across. Here’s what it looks like:

function createArray(object) {
    var array = [];     // We create an empty array.
    for (var key in object) {               // We loop over each key in the input object.
        array.push([object[key], key]);     // We push each object key name and value to the array.
    }
    return array;   // Finally, we return the array.
}

 

With these two functions, you’ll find the rest of the problem to be very easy. Let’s start off by creating the bare-bones for the inventory function. We’ll define the createObject and createArray functions inside it first. We’ll also make sure that we are getting an input array at least, and if not, return an empty array as the result (if we don’t get any inventory, we assume that we have an empty one).

function inventory(arr1, arr2) {

    if (!Array.isArray(arr1)) {         // We check if the first argument is an array.
        return [];                      // If not, we return an empty array as result.
    };

    // MAGIC WILL HAPPEN HERE 😀

    // We define the two helper functions that we have created.
    function createObject(array) {
        var obj = {};
        array.forEach(function(current) {
            obj[current[1]] = current[0];
        });
        return obj;
    }

    function createArray(object) {
        var array = [];
        for (var key in object) {
            array.push([object[key], key]);
        }
        return array;
    }
}

 

Let’s start solving the actual problem. First, we’ll make use of the createObject function to create an object out of the first (current inventory) array. Then, we’ll loop over the items of the second (new inventory) array, and item by item, check if that items exists within the current inventory object (remember the Object.prototype.hasOwnProperty() method?).

If the item exists within the object, we add the new quantity to it. But if it doesn’t exist, we simply create a new property on the object and set it’s value:

function inventory(arr1, arr2) {

    if (!Array.isArray(arr1)) {
        return [];
    };

    var currentInventory = createObject(arr1);  // Creates an object out of the current inventory array.

    arr2.forEach(function(current) {            // We loop over the new inventory array.
        if (currentInventory.hasOwnProperty(current[1])) {      // If the current inventory already has the item:
            currentInventory[current[1]] += current[0];         // we simply increase the value for that item inside the object.
        } else {
            currentInventory[current[1]] = current[0];          // If not, we create the new property and set it's value.
        }
    });
    
    function createObject(array) {
        var obj = {};
        array.forEach(function(current) {
            obj[current[1]] = current[0];
        });
        return obj;
    }

    function createArray(object) {
        var array = [];
        for (var key in object) {
            array.push([object[key], key]);
        }
        return array;
    }
}

 

Now, we should be ready to return the result, but first, we need to do two things:

  • Turn our object back into an array using the createArray method.
  • Make sure that the items are returned ordered alphabetically.

The first step is trivial, we’ve done the work already, but for the second, we’ll use the sort method. You can read more about sort here.

Here’s what it looks like:

function inventory(arr1, arr2) {

    if (!Array.isArray(arr1)) {
        return [];
    };

    var currentInventory = createObject(arr1);

    arr2.forEach(function(current) {
        if (currentInventory.hasOwnProperty(current[1])) {
            currentInventory[current[1]] += current[0];
        } else {
            currentInventory[current[1]] = current[0];
        }
    });

    // First, we create the array, we then apply sort.
    return createArray(currentInventory).sort(function(a, b) {
        if (a[1] < b[1]) return -1;     // If the first item's name is lesser than the second's, we return -1
        if (a[1] > b[1]) return 1;      // In the opposite case, we return 1
        return 0;                       // This case should not happen in this example, but if they were to be equal, we return 0.
    });
    
    function createObject(array) {
        var obj = {};
        array.forEach(function(current) {
            obj[current[1]] = current[0];
        });
        return obj;
    }

    function createArray(object) {
        var array = [];
        for (var key in object) {
            array.push([object[key], key]);
        }
        return array;
    }
}

 

And that’s it for Inventory Update! Remember that if anything is unclear, you can email me, ping me on twitter or post a comment below!