3

Is it possible to get the difference of an associative array and a regular array in Javascript?

Ex.

array1 = [5, 1, 3];
array2 = [1 => 15, 2 => 20, 3 => 10, 4 => 5, 5 =>50 ];

The difference would be...

diff = [2 => 20, 4=> 5];
JohnSmith
  • 1,457
  • 2
  • 18
  • 27
  • 5
    Your second array should be an object, not an array (JavaScript doesn't *have* associative arrays as such). And indeed, pasting the above into the JavaScript console in Chrome reports: "SyntaxError: Unexpected token >" Further: potential dupe, at: http://stackoverflow.com/questions/1187518/javascript-array-difference – David Thomas Jul 09 '12 at 00:21
  • Your second array isn't valid JavaScript. – Brandon Boone Jul 09 '12 at 00:22
  • Do you mean the second array should be like... array2[1] = 15? – JohnSmith Jul 09 '12 at 00:25
  • If I understand this correctly, the `diff` should deliver only those _values_ that are contained in array2, but not in array1. However, array2 has the values `15, 20, 10, 5, 50`, thus the diff would have to be `[15, 20, 10, 50]`, since 1 and 3 are only _keys_ of array2. Kudos for messing up JS object notation with Perl hash notation, though, happens to me all of the time, when I'm doing both within a short stretch of time or switching back and forth. – yogibimbi Apr 15 '13 at 19:49

4 Answers4

4

I assume your question just had a small typo in your declaration of array2. This is not a big deal.

Anyway, here is a bit of hack, but it gives you what you want:

array1 = [5, 1, 3];
array2 = {1: 15, 2: 20, 3: 10, 4: 5, 5: 50};

var result = {};
for (var i in array2) {
    if (array1.indexOf(+i) < 0) {
        result[i] = array2[i];
    }
}

alert(JSON.stringify(result));

Working example

My hack is the +i in the indexOf call, because the properties of your "associative array" are strings, but your array1 contains numbers. The unary + produces a number from a string. Kind of hackish but it is idiomatic an accepted JavaScript practice.

ADDENDUM

As RobG points out, indexOf is an ES5 method, so if your JavaScript engine is ES3 or below, you will need to implement indexOf on your own. An example of how to do this is at MDN. Alternatively, you can just do the equivalent of indexOf by searching the array on your own.

Ray Toal
  • 86,166
  • 18
  • 182
  • 232
3

First of all, your second array should be an object and isn't valid JavaScript, as the first two commenters said. Here it is in object form:

var object = { "1": 15, "2": 20, "3": 10, "4": 5, "5": 50 };

This function achieves your desired result:

function findDiff(arr, obj)
{
    var tempObj = clone(obj);
    for (var i = 0; i < arr.length; i++)
    {
        var propId = arr[i];
        if (tempObj[propId] !== undefined)
            delete tempObj[propId];
    }
    return tempObj;
}

This function relies on a function called clone, which makes sure obj is copied to tempObj by value rather than reference. This prevents the passed object from being modified:

function clone(obj){
    if(obj == null || typeof(obj) != 'object')
        return obj;

    var temp = obj.constructor(); // changed

    for(var key in obj)
        temp[key] = clone(obj[key]);
    return temp;
}

Just call it like this:

var array = [5, 1, 3];
var object = { "1": 15, "2": 20, "3": 10, "4": 5, "5": 50 };

var diff = findDiff(array, object);
jeff
  • 8,300
  • 2
  • 31
  • 43
  • 1
    Note that the assignment of `tempObj = obj` effectively does nothing useful, the function returns the modified original object, not a copy. Also, the property name to be deleted should be checked before attempting to delete it (see [ES5 delete operator](http://es5.github.com/#x11.4.1)) as it may throw an error in strict mode. – RobG Jul 09 '12 at 02:35
  • You're right, nice catch (especially on my shallow copy, I don't know how I missed that). Edited my answer. – jeff Jul 09 '12 at 02:55
2

You will need to explain in detail what you expect the result of the operation to be.

One interpretation is to remove members from one array based on the values in another, so given:

array1 = [5, 1, 3];
array2 = [15, 20, 10, 5, 50 ];

You might have a function:

function diff(arr1, arr2) {
  // Copy arrays so don't affect originals
  var t1 = arr1.slice();
  var t2 = arr2.slice();

  // sort t1
  t1.sort();

  // Remove members of arr2 from highest indexes to lowest
  var i = t1.length;
  while (i--) {
    t2.splice(t1[i], 1);
  }
  return t2;
} 

 alert(diff(array1, array2));  // 15, 10, 50

Note that arrays are zero indexed and there is no 5th member in array2, so the removed values are 20 and 5 (i.e. members with index 1 and 3 respectively).

RobG
  • 142,382
  • 31
  • 172
  • 209
0

Another option would be, to do a JSON.stringify() on your variable and check the leftmost or rightmost character of the resulting string. If it is { or }, you have an associative array / object, if [ or ], it is an array. Which I imagine might be a bit costly, depending on the size of your array, but it would do the job.

However... since there is no such thing as a free lunch, and all animals come in pairs, this is only a reasonable solution, if you have used your variable consequently according to your original definition.
If you defined an object, like so: obj = [1,2,3] and then, at a later point, added a value such as obj['w'] = 'ww', a JSON.stringify(obj) would only produce [1,2,3], but if you addressed obj['w'] again, you would still get ww, meaning that the value is not forgotten, they just don't mix. Internally, I would imagine, that javascript keeps two separate variable tables, one for objects and one for arrays, and whichever has been defined first, gets the nod when printed with stringify.

And to confuse things still more, if you define a variable as object first, but then add an array key, aka

obj = {1: 11, 2: 22, 3: 33};
obj[4] = 44;

the new key is automatically cast as a string, thus yielding a result in stringify of

{"1":11, "2": 22, "3": 33, "4": 44}  //sans the \", for better readibility

Confusing as hell, but I guess that's the price you pay for a little anarchy and ease of use.

yogibimbi
  • 588
  • 5
  • 17