15

For some reason I'm having some serious difficulty wrapping my mind around this problem. I need this JS function that accepts 2 arrays, compares the 2, and then returns a string of the missing element. E.g. Find the element that is missing in the currentArray that was there in the previous array.

function findDeselectedItem(CurrentArray, PreviousArray){

var CurrentArrSize = CurrentArray.length;
var PrevousArrSize = PreviousArray.length;

// Then my brain gives up on me...
// I assume you have to use for-loops, but how do you compare them??

return missingElement;

}

Thank in advance! I'm not asking for code, but even just a push in the right direction or a hint might help...

1
  • 1
    You need to compare each element of array A to each element of array B. There a ways to speed up the process though if you know which kind of values you are comparing. Commented Mar 16, 2012 at 12:05

5 Answers 5

34

12 years later... in ES6, people coming to this for a quick answer can use:

prevArray = .....;
newArray = .....;

function firstElemNotIn(curArray, prevArray) {
    /*
        returns the first element in currentArray that 
          is not in also in previousArray, 
          or undefined if no such element exists
        
        We declare two elements are equal here if they are === or both NaN.
        See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness#comparing_equality_methods
    */
    
    let prevSet = new Set(prevArray);
    return curArray.find(x=> !prevSet.has(x));
}

(This does an O(n) pass to initialize a new Set from the array, then queries that Set in O(1) time per element within .find (so O(n) worst case if it reaches the end of newArray). If you perform this operation repeatedly while updating previousArray repeatedly, you will want to use a different or custom data structure.)

Note that in such problems, regardless of the language, one must be especially careful to note which notion of equality one is using, as otherwise you may encounter subtle bugs ([1,2]!=[1,2], NaN!==NaN, etc.).


[ Original as follows, using javascript as it existed in 2012, except some readability edits... ]


Problem statement:

Find the element that is missing in the currentArray that was there in the previous array.

previousArray.filter(function(x) {  // return elements in previousArray matching...
    return !currentArray.includes(x);  // "this element doesn't exist in currentArray"
})

The above is as bad as writing two nested for-loops, i.e. O(N2) time*). This can be made more efficient if necessary, by creating a temporary object out of currentArray, and using it as a hashtable for O(1) queries. For example:

var inCurrent = {};
for(let x of currentArray) {
    inCurrent[x] = true;
}

So then we have a temporary lookup table, e.g.

previousArray = [1,2,3]
currentArray = [2,3];
inCurrent == {2:true, 3:true};

Then the function doesn't need to repeatedly search the currentArray every time which would be an O(N) substep; it can instantly check whether it's in currentArray in O(1) time. Since .filter is called N times, this results in an O(N) rather than O(N2) total time:

previousArray.filter(function(x) {
    return !inCurrent[x]
})

Alternatively, here it is for-loop style:

var inCurrent = {};
var removedElements = []
for(let x of currentArray)
    inCurrent[x] = true;
for(let x of previousArray)
    if(!inCurrent[x])
        removedElements.push(x)
        //break; // alternatively just break if exactly one missing element
console.log(`the missing elements are ${removedElements}`)

Or just use modern data structures, which make the code much more obvious:

var currentSet = new Set(currentArray);
return previousArray.filter(x => !currentSet.has(x))

*(sidenote: or technically, as I illustrate here in the more general case where >1 element is deselected, O(M*N) time)

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

3 Comments

This is a fabulous answer; gotta love functional programming. Some more work is needed to get it working in non JS1.6 browsers though. Luckily Mozilla has done that work for us in the compatibility sections here: indexOf and here: filter
Strangely enough, while this answer is the nicest, I've got the missing element by returning it when checking for element === -1, not !== -1: In ES6: previousArray.filter(prev => currentArray.indexOf(prev) === -1
@JeanmichelCote: ah whoops, I'm amazed no one caught that in four years... I misread the problem to think that the element was missing from the wrong array. Edited.
4

This should work. You should also consider the case where the elements of the arrays are actually arrays too. The indexOf might not work as expected then.

function findDeselectedItem(CurrentArray, PreviousArray) {

   var CurrentArrSize = CurrentArray.length;
   var PreviousArrSize = PreviousArray.length;

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

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

   }

   return null;

}

1 Comment

doesnt work when we have duplicate entries say previousArray=[5,5,7,7] and currentArray=[5,7,7]..returns null then
2

Take a look at underscore difference function: http://documentcloud.github.com/underscore/#difference

5 Comments

Wow that's great, what does it return though? An array or a single string variable?
@DeanGrobler: => [1, 3, 4] looks like an array. Why would you want a string? You can convert an array to a string easily anyways.
@Felix Kling - That sounds right yes, just wanted to make sure. Thanks :-)
It returns an array. If you've got only one missing element you probably want to use it _.difference(CurrentArray,PreviousArray)[0]. P.S. underscore is a great library. I use it in almost every project. Give it a try.
Name has been changed to lodash and you can find it here: lodash.com/docs/4.17.15#differenceBy. Works great for obj arrays.
1

I know this is code but try to see the difference examples to understand the way:

var current = [1, 2, 3, 4],
    prev = [1, 2, 4],
    isMatch = false,
    missing = null;

var i = 0, y = 0,
    lenC = current.length,
    lenP = prev.length;

for ( ; i < lenC; i++ ) {
    isMatch = false;
    for ( y = 0; y < lenP; y++ ) {
        if (current[i] == prev[y]) isMatch = true;
    }
    if ( !isMatch ) missing = current[i]; // Current[i] isn't in prev
}

alert(missing);

Or using ECMAScript 5 indexOf:

var current = [1, 2, 3, 4],
    prev = [1, 2, 4],
    missing = null;

var i = 0,
    lenC = current.length;

for ( ; i < lenC; i++ ) {
    if ( prev.indexOf(current[i]) == -1 ) missing = current[i]; // Current[i] isn't in prev
}

alert(missing);

And with while

var current = [1, 2, 3, 4],
    prev = [1, 2, 4],
    missing = null,
    i = current.length;

while(i) {
    missing = ( ~prev.indexOf(current[--i]) ) ? missing : current[i];
}

alert(missing);

1 Comment

Using this we can not get all missing elements.
-1

This is my approach(works for duplicate entries too):- //here 2nd argument is actually the current array

function(previousArray, currentArray) {
    var hashtable=[]; 

    //store occurances of elements in 2nd array in hashtable
    for(var i in currentArray){
        if(hashtable[currentArray[i]]){
            hashtable[currentArray[i]]+=1; //add 1 for duplicate letters
        }else{
            hashtable[currentArray[i]]=1; //if not present in hashtable assign 1
        }
    }
    for(var i in previousArray){
            if(hashtable[previousArray[i]]===0 || hashtable[previousArray[i]] === undefined){ //if entry is 0 or undefined(means element not present)
                return previousArray[i]; //returning the missing element
            }
    else{
             hashtable[previousArray[i]]-=1; //reduce count by 1
        }

    }
}

Logic is that i have created a blank array called hashtable. We iterate currentArray first and use the elements as index and values as counts starting from 1(this helps in situations when there are duplicate entries). Then we iterate through previousArray and look for indexes, if they match we reduce the value count by 1. If an element of 2nd array doesnt exist at all then our undefined check condition fires and we return it. If duplicates exists, they are decremented by 1 each time and when 0 is encountered, that elment is returned as missing element.

Comments

Your Answer

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