In this problem, you’ve to compare and update the inventory stored in a 2D array against a second 2D array of a fresh delivery. Update the current existing inventory item quantities (in arr1). If an item cannot be found, add the new item and quantity into the inventory array. The returned inventory array should be in alphabetical order by item.
The current as well as new inventory will be in this format: [[2, "item-0"], [3, "item-1"], [67, "item-2"], [7, "item-3"]].
You need to work through each item of the new inventory to see if it exists in the current inventory or not. Remember that the product name is stored as the second element of each sub-array: array[0][1] = "item-name".
Hint 2
If the item exists, you need to add the quantity from the new inventory. If the item doesn’t exist, you need to add the entire item.
Hint 3
Return the completed inventory in alphabetical order.
Solutions
Solution 1 (Click to Show/Hide)
function updateInventory(currentInventory, newInventory) {
// Check each item of new inventory
for (let newItem of newInventory) {
let found = false;
// Check against current inventory
for (let oldItem of currentInventory) {
// Update value if new item is found
if (newItem[1] === oldItem[1]) {
oldItem[0] += newItem[0];
found = true;
break;
}
}
// Otherwise add item to the old inventory
if (!found) currentInventory.push([...newItem]);
}
// Alphabetize and put into original array format
return currentInventory
.sort((a, b) => {
if (a[1] < b[1]) return -1;
if (a[1] > b[1]) return 1;
return 0;
});
}
Code Explanation
Here we use a nested loop to locate the value of the new item in the old inventory array and update it.
If the new item is not found, the it is added to the end of the old array.
Lastly, the original array is sorted.
Note, this mutates the input array.
Solution 2 (Click to Show/Hide)
function updateInventory(currentInventory, newInventory) {
const combinedInventory = {};
// Account for all old inventory
for (let item of currentInventory) {
combinedInventory[item[1]] = item[0];
}
// Account for all new inventory
for (let item of newInventory) {
combinedInventory[item[1]] ??= 0;
combinedInventory[item[1]] += item[0];
}
// Alphabetize and put into original array format
return Object.keys(combinedInventory)
.sort()
.map(item => [combinedInventory[item], item]);
}
Code Explanation
In this solution, we use an object as a hash table to de-nest the two loops. This approach trades time complexity for space complexity.
function updateInventory(current, shipment) {
//combine all inventory together
var inventory = current.concat(shipment);
var length = inventory.length, i = 0;
//iterate through array
while (i < length) {
var j = i + 1;
//seek and destroy duplicates; decrease length when one is destroyed
while(j < length) {
if(inventory[i][1] === inventory[j][1]) {
inventory[i][0] += inventory[j][0];
inventory.splice(j, 1);
length--;
}
j++;
}
i++;
}
//sort ascending by product name
return inventory.sort(function(a, b) {
if(a[1] < b[1])
return -1;
if(a[1] > b[1])
return 1;
});
}
I think my solution works pretty good and is comparable to the given solution up top. Any critiques?
Thank you!
function updateInventory(arr1, arr2) {
//iterate through each item in the second array
for (var i = 0; i < arr2.length; i++) {
var foundMatch = false;
//Does the current item match any existing items? If so, update their quantity
for (var n = 0; n < arr1.length; n ++) {
if (arr1[n][1].indexOf(arr2[i][1]) !== -1) {
arr1[n][0] += arr2[i][0];
//Make foundMatch true so it doesnt add the item later, outside of this iteration
foundMatch = true;}
}
//Did iterating through the array turn up a match?
if (foundMatch === false) {
//if not, create new item
arr1.push(arr2[i]);}
}
//final step, sort everything that is in the array
arr1.sort(function(a, b) {
if (a[1] < b[1]) {
return -1; }
return 1;
});
return arr1;
}
// Example inventory lists
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"]
];
updateInventory(curInv, newInv);
I think I found a much simpler way to solve this using basic code. Simply concat the two arrays, sort them by the item names, then loop through them, starting from the end of the array, adding the totals and splicing out the duplicate arrays.
function updateInventory(arr1, arr2) {
//concatenate the argument arrays
arr1 = arr1.concat(arr2);
//sort the array by the item names
arr1.sort(function(a, b){
return a[1] > b[1];
})
//Set up a loop to go through each array, starting from the end. Note you have to end when i is 1.
for (var i = arr1.length - 1; i >= 1; i--){
//check to see if each name matches the one ahead of it
if (arr1[i][1] === arr1[i-1][1]){
//if you find a match, add the numbers
arr1[i-1][0] += arr1[i][0];
// then splice out the duplicate
arr1.splice(i, 1);
}
}
return arr1
}
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"]
];
updateInventory(curInv, newInv);
I got to 142, but only by removing every possible character AND changing the names of the function and arguments. The function alone has 14 more characters than it really needs.
function u(x,y){x=x.concat(y).sort((a,b)=>a[1]>b[1]);for(i=x.length-2;i--;){if(x[i][1]==x[i+1][1]){x[i+1][0]+=x[i][0];x.splice(i,1)}}return x}
Mine is a bit clumsy, but I did not see anyone go this way so here it is:
function updateInventory(arr1, arr2) {
// Arrey to hold all items' names
var itemList = [];
// Turn the arr1 into a JSON
var inv = arr1.reduce(function (acc, a) {
acc[a[1]] = {amount:a[0]};
itemList.push(a[1]);
return acc;
}, {});
// Check each item from the arr2 against the inventory
for (i = 0; i < arr2.length; i++) {
// Add amount if item is present
if (inv[arr2[i][1]]) {inv[arr2[i][1]].amount += arr2[i][0];}
else {
// Create new item in inv if not present
itemList.push(arr2[i][1]);
inv[arr2[i][1]] = {amount:arr2[i][0]};
}
}
// Generate the result based on the alphabetically sorted itemList
return itemList.sort().reduce(function(acc, item) {
acc.push([inv[item].amount, item]);
return acc;
},[]);
}
function updateInventory(arr1, arr2) {
var A = [];
var currInvObj = arr1.reduce(function(obj, arr) {
obj[arr[1]] = arr[0];
return obj;
}, { });
for (var i = 0; i < arr2.length; i++) {
if (currInvObj.hasOwnProperty(arr2[i][1])) currInvObj[arr2[i][1]] += arr2[i][0];
else A.push([arr2[i][0], arr2[i][1]]);
}
for ( var prop in currInvObj) {
A.push([currInvObj[prop], prop]);
}
A.sort((a, b) =>a[1] > b[1]);
return A;
}
function updateInventory(arr1, arr2) {
// All inventory must be accounted for or you're fired!
var items = {};
for (var i = 0; i < arr1.length; i++) {
items[arr1[i][1]] = arr1[i][0];
}
for (i = 0; i < arr2.length; i++) {
items[arr2[i][1]] = items[arr2[i][1]] === undefined ? arr2[i][0] : items[arr2[i][1]] + arr2[i][0];
}
result = [];
for (item in items) {
result.push([items[item], item]);
}
return result.sort((a,b) => a[1] > b[1]);
}
Here is my solution by converting the current inventory to an object for easy data manipulation and using Sting.prototype.localeCompare() to sort when converted back to an array:
function updateInventory(arr1, arr2) {
//Make copies of the arrays for clarity sake
var copy_curInv = arr1, copy_newInv = arr2,
//convert current inventory to an object for easy data manipulation
objCurInv = copy_curInv.reduce(function(acc, cur){
acc[cur[1]] = cur[0];
return acc;
}, {}),
//sorted
sortedArr = [];
//Loop thru the new inventory and update or create new inventory
copy_newInv.forEach(function(inv){
//If new inventory exists in current inventory,
if(objCurInv.hasOwnProperty(inv[1])){
objCurInv[inv[1]] += inv[0]; //update it's quantity (by increment)
}else{//OR
objCurInv[inv[1]] = inv[0]; //create a new inventory
}
});
//Convert the updated current inventory back to an array
for(var currInv in objCurInv){
sortedArr.push([objCurInv[currInv], currInv]);
}
//sort alphabetically using String.prototype.localeCompare()
sortedArr.sort(function(a, b){
return a[1].localeCompare(b[1]);
});
return sortedArr; //The result
}
Here is my own solution, without a loop within a loop, separating the names make it possible.
function updateInventory(arr1, arr2) {
// All inventory must be accounted for or you're fired!
// get all our current inventory items, so we can reference it later.
var items = arr1.map(function(item){
return item[1];
});
return arr2.reduce(function(inventory,item){
var i = items.indexOf(item[1]);
if(i >= 0){
inventory[i][0] += item[0];
}
else{
inventory.push(item);
}
return inventory;
},arr1).sort(function(a,b){ return a[1] > b[1]; });
}
I did this one without sorting. Instead, I inserted the new items in the correct position. I believe it’s more efficient this way since you only go through the arrays once.
function updateInventory(currentInventory, newInventory) {
let updatedInventory = currentInventory;
for (const newItem of newInventory) {
let index = updatedInventory.length;
let existing = false;
for (let i = 0; i < updatedInventory.length; i++) {
if (newItem[1] === updatedInventory[i][1]) {
updatedInventory[i][0] += newItem[0];
existing = true;
break;
}
if (newItem[1] < updatedInventory[i][1]) {
index = i;
break;
}
}
if (!existing) {
updatedInventory = updatedInventory.slice(0, index).concat([newItem], updatedInventory.slice(index));
}
}
return updatedInventory;
}