A friend had asked me about converting a 2-dimensional array into a flat 1-dimensional array. In array form this would be (written as was provided to me):
in = [1,"2",[3,"4"]]; out = [1,"2",3,"4"]; //this is what he wanted out.
Keywords
Given this task I started to code. However, I had forgotten one glaring issue. His code would fail from the start. He could never use the variable “in” because “in” is a reserved keyword in Javascript.
http://www.quackit.com/javascript/javascript_reserved_words.cfm
Reserved keywords are those special words that you can’t use as variables because they have some significant meaning to the Javascript interpreter. In this case “in” is used for certain for loops.
Maybe this was a trick question or maybe he just happened to use those variable names. I changed the input variable and tried to figure out the problem.
Type Checking Variables
My friend also wanted to make sure that the variable being passed into the function was an array. As I somewhat knew already, this type checking brings all sorts of issues with Javascript. “typeof” is a keyword that allows you to check what data type a variable is, but it has some limitations for Arrays and is best used in checking if something is undefined. Arrays will output a typeof “Object” instead of “Array”.
I found that “instanceof” would work, however it has issues if two different objects have the same prototypical attributes. A Javascript object with the class name of “Object” is the same as “Other” if both objects have the same attributes. Doing a bit more research led me to this website which describes a better way to check arrays (and the possibly incorrect ways that systems like JQuery used to use). Doug Crockford suggested Duck Typing in 2003 to address the issue of typing objects and John Resig points out that “as of 1.3 jQuery no longer uses instanceof or .constructor – for the same reasons that you list here. We were especially hitting problems when dealing with cross-frame pages.”
The Code
Without further adieu, here’s the code.
//can't use "in" as a variable! inArr = ["1",[2,["3"]],4,[5,[6,7,8,[9,[10]]]]]; out = flatten(inArr); debug(out); /** * Flattens a multidimensional array into a flat 1D array. * @param arr - a multidimensional array * @param arrOut - Optional, an initial array * @return a flat array */ function flatten(arr, arrOut){ if(typeof arrOut === "undefined") //optional variable var arrOut = []; //new Array or [] work the same //not so easy to simply check if it's an array //http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/ if(Object.prototype.toString.call(arr) === '[object Array]'){ //loop through array values for(var i = 0; i < arr.length; i++){ console.log(i+" - "+arr[i]); //check if there's a sub-array if(Object.prototype.toString.call(arr[i]) === '[object Array]'){ //recurse!! arrOut = flatten(arr[i],arrOut); }else{ //push the value onto the exising array arrOut.push(arr[i]); } } } return arrOut; //return the modified array } //just a helper function to show the array function debug(obj){ out = ""; for(i in obj){ out += i+" - "+obj[i]+"\n"; } alert(out); }