1

The below code is supposed to:

1) go through the two arrays,

2) if an item exist in both arrays, add its value to the value of the similar item in the first array,

3) if the item is found in arr2 but not arr1, add the item to arr1. My code works as desired when both arrays have the same size, but this is what I get with arrays of different size.

Result:

[[42, "Bowling Ball"], [4, "Dirty Sock"], [2, "cat"], [6, "mugs"], [2, "Dirty Sock"], [3, "rags"]]

should be:

[[42, "Bowling Ball"], [4, "Dirty Sock"], [2, "cat"], [3, "rags"], [3, "mugs"]]

And here is my code:

function updateInventory(arr1, arr2) {
  for (var i = 0; i < arr1.length; i++) {
    for (var j = i; j < arr2.length; j++) {
      if (arr1[i][1] === arr2[j][1]) {
        arr1[i][0] += arr2[j][0];
      }
      if (arr1[i].indexOf(arr2[j][1]) === -1) {
        arr1.push(arr2[j]);
      }
      if (arr2.length > arr1.length) {
        arr1.push(arr2[arr2.length -1]);
      }
      else
        break;
    }
  }
  return arr1;
}

var curInv = [
    [21, "Bowling Ball"],
    [2, "Dirty Sock"],
    [2, "cat"],
];

var newInv = [
    [21, "Bowling Ball"],
    [2, "Dirty Sock"],
    [3, "rags"],
    [3, "mugs"]
];

updateInventory(curInv, newInv);

What is the issue here?

2
  • 1
    Is it possible to use a different data structure? A map would be really good here. Commented Oct 21, 2016 at 20:24
  • yes since this is an exercise that I'm doing. but I'm also interested with what is wrong here as well Commented Oct 21, 2016 at 20:26

4 Answers 4

1

You could use a hash table for the inventory and check against and update currInv.

var curInv = [[21, "Bowling Ball"], [2, "Dirty Sock"], [2, "cat"], ],
    newInv = [[21, "Bowling Ball"], [2, "Dirty Sock"], [3, "rags"], [3, "mugs"]],
    inventory = Object.create(null);

curInv.forEach(function (a) {
    this[a[1]] = a;
}, inventory);

newInv.forEach(function (a) {
    if (!this[a[1]]) {
        this[a[1]] = [0, a[1]];
        curInv.push(this[a[1]]);
    }
    this[a[1]][0] += a[0];
}, inventory);

console.log(curInv);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Sign up to request clarification or add additional context in comments.

Comments

0

You are over-complicating things I think. Here's a working snippet.

function updateInventory(arr1, arr2) {
  for (var i = 0; i < arr2.length; i++) {
    var matchFound = false;
    for (var j = 0; j < arr1.length; j++) {
      if (arr1[j][1] === arr2[i][1]) {
        arr1[j][0] += arr2[i][0];
        matchFound = true;
      }
    }

    if (!matchFound) {
      arr1.push(arr2[i]);
    }
  }
  return arr1;
}


var curInv = [
  [21, "Bowling Ball"],
  [2, "Dirty Sock"],
  [2, "cat"],
];

var newInv = [
  [21, "Bowling Ball"],
  [2, "Dirty Sock"],
  [3, "rags"],
  [3, "mugs"]
];

console.log(updateInventory(curInv, newInv));

What it does

  1. Loop through all of the elements in arr2.
  2. Loop through all of the elements in arr1.
  3. If a match is found, add the number of items in arr2 to the corresponding value in arr1.
  4. If no match is found, add that element in arr2 to arr1.

4 Comments

thanks for the answer, Why you start iterating from array 2 and not 1
I notice that you also put the final if statement outside the inner for loop. could you explain why? thanks
@dadadodo If the if statement is inside the loop, what happens if the key (the name of the inventory item) occurs after arr1[i]? In this case, we would be pushing the item to arr1 even though it occurs later in arr1. That isn't what we want.
@dadadodo As to why I iterate arr2 first, it's more efficient. Think about it, what if arr2 has 2 items not already in arr1, but arr1 has 1000 items. We still have to loop through all 1000 records of arr1 even if the items in arr2 occur in arr3 towards the beginning of the array. If we iterate arr2 first, we only iterate through arr1 until we find a match. If the the items in arr2 occur at indices 2 and 10, then we only have to check 12 values in arr1. You can probably think of a situation where this is more inefficient, but this was my thought process.
0

You can merge the arrays Or combine the array so it will automatically do what you want .

var array3 = curInv.concat(newInv);

If you want to find the unique elements

// Merges both arrays and gets unique items var array3 = **

arrayUnique(array1.concat(array2));

function arrayUnique(array) {
   var a = array.concat(); 
   for(var i=0; i<a.length; ++i) { 
          for(var j=i+1; j<a.length; ++j) {
             if(a[i] === a[j]) a.splice(j--, 1); } 
     } 
   return a; 
}

**

1 Comment

Why do you comment on your own answer with more answers? Just edit your answer, and add it in.
0

Here is a concise functional programming style solution that uses a hash (a Map actually) for efficiency:

function updatedInventory(a, b) {
    return Array.from(
        b.reduce( (m, [v,k]) => m.set(k, (m.get(k) || 0) + v),
                   new Map(a.map ( ([v,k]) => [k,v] )) ), // swap pairs
        ([k,v]) => [v,k]) // swap back afterwards;
}

// Sample data
var curInv = [
    [21, "Bowling Ball"],
    [2, "Dirty Sock"],
    [2, "cat"],
];

var newInv = [
    [21, "Bowling Ball"],
    [2, "Dirty Sock"],
    [3, "rags"],
    [3, "mugs"]
];

// call the function
curInv = updatedInventory(curInv, newInv);
// Output the result
console.log(curInv);
.as-console-wrapper { max-height: 100% !important; top: 0; }

If your data would have pairs where the name is in the first element, and the number in the second, the code would have been much shorter. That is because Map objects are initialised with keys - value pairs, not value - key pairs:

function updatedInventory(a, b) {
    return [...b.reduce( (m, [v,k]) => m.set(k, (m.get(k) || 0) + v), new Map(a) )];
}

// Sample data
var curInv = [
    ["Bowling Ball", 21],
    ["Dirty Sock", 2],
    ["cat", 2],
];

var newInv = [
    ["Bowling Ball", 21],
    ["Dirty Sock", 2],
    ["rags", 2],
    ["mugs", 2]
];

// call the function
curInv = updatedInventory(curInv, newInv);
// Output the result
console.log(curInv);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Because this function does not mutate the passed arguments, but returns the result, I have called it updatedInventory instead of updateInventory.

Issues with the code you tried with

  1. your outer loop is on the first array, but that is not very practical, as you'll have a difficult time to identify the values that are missing in it. You should really loop over the second array first. Then you will find the elements that are missing in the first array.

  2. There seems no good reason to start the inner loop at the index the outer one is currently at. So you'd better start at 0. Together with the first point, this would make your loops look like this:

    for (var j = 0; j < arr2.length; j++) {
      for (var i = 0; i < arr1.length; i++) {
    
  3. When finding a match, there is no reason to look further, so you should then exit the inner loop:

        if (arr1[i][1] === arr2[j][1]) {
          arr1[i][0] += arr2[j][0];
          break;
        }
    
  4. The second if you have, is really initiating a third loop, as indexOf performs an iteration. Furthermore, you are looking in arr1[i] which only has two elements: a value and a key. That was not your intension, I'm sure.

    Instead this code should be moved outside of the inner loop, and be corrected to look like this (again, taken into account your loops are swapped according to point 2):

      if (i >= arr1.length) { // this indicates no match was found
        arr1.push(arr2[j]);
      }
    
  5. The third if was trying to align the length of the array, but it could well add an element that was already present in the other array! So that just has to go. In fact, the previous suggested correction would already make the arrays get aligned.

  6. The break you have really killed it, and made you miss matches, and is the core reason (together with problem 4) why you got a duplicate. There is no reason to break here, as the first if might be true in one of the next iterations, so you should give that a chance still.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.