Archive

Archive for the ‘javascript’ Category

Ruby-like difference between two arrays in JavaScript

January 15th, 2009

Ruby has a nifty feature that allows you to “subtract” two arrays. e.g.

Fruit = ["Apple", "Kinnow", "Mango", "Orange"]
Citrus = ["Lemon", "Kinnow", "Orange", "Tangerine"]

Then Fruit – Citrus gives:
["Apple", "Mango"]

Notice that elements in Citrus not in Fruit (Lemon, Tangerine) are not in the difference.

Now I needed something similar in Javascript. So I started by pushing my luck:

var Fruit = ["Apple", "Kinnow", "Mango", "Orange"];
var Citrus = ["Lemon", "Kinnow", "Orange", "Tangerine"];
var Diff = Fruit - Citrus;

Depending on where you are running this code, Diff will be 0 or NaN. This meant that I would have to come up with something of my own. I figured I’ll put javascript’s regular expressions to some use and came up with this:

function diffArrays (A, B) {

  var strA = ":" + A.join("::") + ":";
  var strB = ":" +  B.join(":|:") + ":";

  var reg = new RegExp("(" + strB + ")","gi");

  var strDiff = strA.replace(reg,"").replace(/^:/,"").replace(/:$/,"");

  var arrDiff = strDiff.split("::");

  return arrDiff;
}

diffArrays(Fruit, Citrus) gives:
["Apple", "Mango"]

The thing with dynamically typed languages is that you can take even numeric arrays through this regular expression rigmarole and get a correct result back without anyone complaining:

var Natural = [1,2,3,4,5,6];
var Prime = [1,2,3,5,7];

diffArrays(Natural, Prime) gives:
[4, 6]

A brief explanation of how this works:

I start by converting the first array to a string delimited with two colons, :: – the choice was arbitrary. The fact that regular expressions don’t treat a colon any specially helps. I then prefix and suffix the resulting string with another colon. The idea here is to have each element “surrounded” by its own pair of colons. For instance, [1,2,3,4,5,6] becomes :1::2::3::4::5::6:

The array to be subtracted from it – say [1,2,3,5] is converted to the form – :1:|:2:|:3:|:5: which I then use to create a regular expression. The pipe | has a special meaning in the regular expression world and will cause :1: or :2: or :3: or :5: to be matched.

Calling strA.replace with our just-crafted regular expression replaces :1:, :2:, :3: and :5: with “” giving us :4::6:, which I strip clean of the leading and trailing colons through another couple of replace calls. Finally, spitting the string on :: gives the delta array!

Now this implementation is certainly not going to win me any prizes in speed/elegance pageants, but I think this somewhat awkward application of regular expression was something worth sharing!

On a somewhat related note, a special thanks goes out to Steve Yegge for his wonderful js2-mode and ejacs. The latter especially comes in handy when you are just “doodling” around on JavaScript problems like these.

javascript , ,