jskidd3
jskidd3

Reputation: 4783

Finding missing array in array of arrays

I need to find a missing array in an "array of arrays". I started by finding this function below (on StackOverflow):

function findDeselectedItem(CurrentArray, PreviousArray) {

   var CurrentArrSize = CurrentArray.length;
   var PreviousArrSize = PreviousArray.length;
   var deselectedItem = [];

   // loop through previous array
   for(var j = 0; j < PreviousArrSize; j++) {

      // look for same thing in new array
      if (CurrentArray.indexOf(PreviousArray[j]) == -1)
         deselectedItem.push(PreviousArray[j]);

   }

   return deselectedItem;
}

This works just fine if you did something like this:

oldarray = ["hi", "ho", "hey"];
newarray = ["hi", "hey"];

Using findDeselectedItem(newarray, oldarray) would return ["ho"].

However, my content looks like this:

oldarray = [["James", 17, 1], ["Olivia", 16, 0], ["Liam", 18, 1]];
newarray = [["Olivia", 16, 0], ["James", 17, 1]];

How can I adapt the function above so that it returns the missing array containing 'Liam'.

Thanks

Upvotes: 1

Views: 138

Answers (6)

Michael Antipin
Michael Antipin

Reputation: 3532

I would make a hash with the name as a key. That would make finding missing content trivial and very fast. You can then optimize the method by not rebuilding the hash every time, but only when it's really necessary.

var oldArray = [["James", 17, 1], ["Olivia", 16, 0], ["Liam", 18, 1]];
var newArray = [["Olivia", 16, 0], ["James", 17, 1]];

function findDeselectedItems(oldArray, newArray)
{
   var results = [];

   var hash = {};
   for (var i=0; i<newArray.length; i++) {          
      hash[newArray[i].join(',')] = true;
   }

   for (var i=0; i<oldArray.length; i++) {
      if (!hash[oldArray[i].join(',')]) {
        results.push(oldArray[i]);
      }   
   }

   return results;
}   

Upvotes: 2

cirrus
cirrus

Reputation: 5662

I don't think you can use indexOf to compare two arrays. You need a deeper comparison. Although this code could be written another way, you could do this with an array comparison function and using Array.some() to filter through your elements. Here's an example and a fiddle;

// Credit http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript
// attach the .compare method to Array's prototype to call it on any array
Array.prototype.compare = function (array) {
    // if the other array is a falsy value, return
    if (!array)
        return false;

    // compare lengths - can save a lot of time
    if (this.length != array.length)
        return false;

    for (var i = 0; i < this.length; i++) {
        // Check if we have nested arrays
        if (this[i] instanceof Array && array[i] instanceof Array) {
            // recurse into the nested arrays
            if (!this[i].compare(array[i]))
                return false;
        }
        else if (this[i] != array[i]) {
            // Warning - two different object instances will never be equal: {x:20} != {x:20}
            return false;
        }
    }
    return true;
}

function findDeselectedItem(CurrentArray, PreviousArray) {

    var CurrentArrSize = CurrentArray.length;
    var PreviousArrSize = PreviousArray.length;
    var deselectedItem = [];

    // loop through previous array
    for (var j = 0; j < PreviousArrSize; j++) {
        // look for same thing in new array
        CurrentArray.some(function (a, idx) {
            if(PreviousArray[j].compare(a) == false) {
                deselectedItem.push(PreviousArray[j]);
                return true;
            }
        });
    }

    return deselectedItem;
    }

var oldarray =[["James", 17, 1], ["Olivia", 16, 0], ["Liam", 18, 1]];
var newarray =[["Olivia", 16, 0], ["James", 17, 1]];

console.log(findDeselectedItem(newarray, oldarray));

Upvotes: 0

prasun
prasun

Reputation: 7343

function findDeselectedItem(CurrentArray, PreviousArray) {

    var CurrentArrSize = CurrentArray.length;
    var PreviousArrSize = PreviousArray.length;
    var deselectedItem = [];
    var selectedIndices = [];

  // loop through previous array
  for(var j = 0; j < PreviousArrSize; j++) {

   for(k=0; k < CurrentArrSize ; k++){
      if (CurrentArray[k].toString() === PreviousArray[j].toString()){
          selectedIndices.push(j);
          break;
      }

   }

 }

    for(var l = 0; l < PreviousArrSize; l++){
      if(selectedIndices.indexOf(l) === -1){
         deselectedItem.push(PreviousArray[l]);
      }
    }

      return deselectedItem;
}

Upvotes: 0

Hashbrown
Hashbrown

Reputation: 13023

The problem may be that indexOf uses strict equality. I.e. if an item in the 'previous' array isn't literally also in the 'current' array, it will report it to not be in there.

You will have to iterate over the values yourself (instead of using indexOf) and check if the array contains something that is 'the same as' (but not literally the same) the array.

I.e. if I didn't explain myself well enough take a look at this;

['bob'] == ['bob']; //false
//therefore
[['bob']].indexOf(['bob']); //-1

Upvotes: 1

Carsten Massmann
Carsten Massmann

Reputation: 28196

@KarelG: nice and quick solution but should it not be var checkArray = PreviousArr[j]; instead of var checkArray = PreviousArrSize[j]; ?

Upvotes: 0

KarelG
KarelG

Reputation: 5244

I hope that this helps you,

function findDeselectedItem(CurrentArray, PreviousArray) {

    var CurrentArrSize = CurrentArray.length;
    var PreviousArrSize = PreviousArray.length;
    var deselectedItem = [];

    // loop through previous array
    for(var j = 0; j < PreviousArrSize; j++) {
        var checkArray = PreviousArrSize[j];
        // loop through 2nd array to match both array

        for(var i = 0; i < CurrentArrSize; i++) {
            // look for same thing in new array
            if (CurrentArray[i].indexOf(checkArray) == -1)
                deselectedItem.push(CurrentArray[i]);

        }
    }
    return deselectedItem;
}

Upvotes: 0

Related Questions