Tag Archives: Array

JavaScript – Array.prototype.randomize()

Here is a little snippet that you may find useful if you ever have to randomize the contents of an array:

Array.prototype.randomize = function() {
  var t, j, ret = this.slice(0), i = ret.length;
  while(--i > 0) {
    t = ret[j = Math.round(Math.random() * i)];
    ret[j] = ret[i];
    ret[i] = t;
  }
  return ret;
};

Here is an example of how to use it with an array:

// The array of random names.
var names = [
  "Amy",
  "Greg",
  "Jen",
  "Matthew",
  "Owen",
  "Richard",
  "Stacy",
  "Tiffany",
  "Victoria",
  "Wanda"
];
// Randomize the array of names.
var randomOrder = names.randomize();
// Display the names.
alert("This will be the order:\n- " + randomOrder.join("\n- "));

The above example will show the names that are in the names array in random order. If we are using a JavaScript library that defines Array.prototype.map()) (such as jPaq) or we know that the page will be viewed on newer browsers (such as Firefox 3.5+ or Google Chrome), we could take the following approach to actually display the number order next to each name:

// The array of random names.
var names = [
  "Amy",
  "Greg",
  "Jen",
  "Matthew",
  "Owen",
  "Richard",
  "Stacy",
  "Tiffany",
  "Victoria",
  "Wanda"
];
// Randomize the array and display the number of each name to the left of the
// name.
var randomOrder = names.randomize().map(function(name, i) {
  return ++i + ". " + name;
});
// Display the names in random order.
alert("This will be the order:\n" + randomOrder.join("\n"));

JavaScript – Logical Operator Array Functions

As a follow-up to my previous article about the AND (&&) and OR (||) logical operators, I decided to create to Array prototype functions that mimic these operators to a certain degree:

// If array is empty, undefined is returned.  If not empty, the first element
// that evaluates to false is returned.  If no elements evaluate to false, the
// last element in the array is returned.
Array.prototype.and = function() {
  for(var i = 0, len = this.length - 1; i < len && this[i]; i++);
  return this[i];
};

// If array is empty, undefined is returned.  If not empty, the first element
// that evaluates to true is returned.  If no elements evaluate to true, the
// last element in the array is returned.
Array.prototype.or = function() {
  for(var i = 0, len = this.length - 1; i < len && !this[i]; i++);
  return this[i];
};

Here are two examples of using a series of AND (&&) operators and then doing the same thing with the Array’s new and() function to produce the same result:

// Both will show null:
alert(true && 3.14 && null && "false" && 0 && window);
alert([true, 3.14, null, "false", 0, window].and());

// Both will show "Chris West":
alert(Math.PI && alert && true && /regexp/ && {key:"value"} && "Chris West");
alert([Math.PI, alert, true, /regexp/, {key:"value"}, "Chris West"].and());

Here are two examples of using a series of OR (||) operators and then doing the same thing with the Array’s new or() function to produce the same result:

// Both will show 3.14:
alert(0 || null || 3.14 || true || "false" || undefined || window);
alert([0, null, 3.14, true, "false", undefined, window].or());

// Both will show 0:
alert(undefined || null || false || 0);
alert([undefined, null, false, 0].or());

As you can see, this function approach could prove useful in cases where you have a variable amount of values stored in an array that you need to test out. The main difference to note is the fact that when using the logical operators instead of the array of values, you know that only the things that need to be executed are executed. Look at the following example to see what I mean:

var obj = {key : "value"};

// Shows undefined:
alert(obj && obj.key && obj.key.length && obj.key2 && obj.key2.length);

// Results in an error because obj.key2 is undefined and thus doesn't have a length property.
alert([obj, obj.key, obj.key.length, obj.key2, obj.key2.length].and());

The beauty of the AND and OR operators is the fact that they are short-circuit operators. In other words, each part of the expression is executed from left-to-right until the answer can clearly be determined from the values that are found. For my example, since obj.key2 doesn’t exist, there is no reason to go any further to evaluate the expression full of &&’s. On the other hand, when we put all of the values in the array, these values are immediately evaluated. Therefore, since obj.key2 is undefined and undefined can’t have any properties, an error occurs and prevents the construction of the array. For this reason, these prototypal functions are very similar to using the logical operators but don’t always produce the same results because of how the statements execute.

JavaScript – forEach with Breaking

It seems that one of the top complaints about the Array.prototype.forEach() function is the fact that there is no easy way to break out of the loop. If you are one of those people that would like to see an implementation, here you go:

function forEach(arr, fn, thisObj) {
  // Try-catch surrounds the loop to allow throwing the array as an equivalent
  // for breaking out of the loop.
  try {
    for(var i = 0, len = arr.length; i < len; i++) {
      fn.call(thisObj, arr[i], i, arr);
    }
  }
  catch(e) {
    // If the error thrown was not the array, allow the error to continue up the
    // stack.
    if(e !== arr) {
      throw e;
    }
  }
  
  // Return a reference to the array to all for further manipulation.
  return arr;
}

Calling this function would be similar to using Array.prototype.forEach.call() to call the forEach() function introduced in JavaScript 1.6. Here is an example call will break out of the loop as soon a perfect square is found:

var perfectSquare;
forEach([2,3,5,6,7,8,9,10,16], function(num, index, arr) {
  var sqrt = Math.sqrt(num);
  if(sqrt == parseInt(sqrt, 10)) {
    perfectSquare = num;
    throw arr;
  }
});

alert(perfectSquare);  // first perfect square found

For proof that this actually works, you can check out this JSBin page.

As you see in the code, in order to break out of the loop, you will need to throw the array that you are traversing. As you may have guessed, you can also fake the continue action by simply using return.

JavaScript – Add Commas To Numbers

At times, I have had to add commas to numbers in order to make them look better in different applications. Even though there isn’t a native way to do this in JavaScript, the code can be quite short, sweet and to the point:

function addCommas(intNum) {
  return (intNum + '').replace(/(\d)(?=(\d{3})+$)/g, '$1,');
}

The downside of the above function is that it will only work for integers. Here is a function that will get the job done for one number or a string which contains one or more numbers:

function delimitNumbers(str) {
  return (str + "").replace(/\b(\d+)((\.\d+)*)\b/g, function(a, b, c) {
    return (b.charAt(0) > 0 && !(c || ".").lastIndexOf(".") ? b.replace(/(\d)(?=(\d{3})+$)/g, "$1,") : b) + c;
  });
}

First this function forces the parameter that was passed in to become a string. Next, a global replace of a regular expression looking for a four-digit or longer number goes through and inserts the commas in the correct place. After that, the result is returned as a string.

Here are some tests that I ran on the function to make sure that it works correctly:

// Delimit a random number.
alert("Random number:  " + delimitNumbers(Math.random() * (1 << 30)));

// Delimit all powers of 2 (from 2^0 to 2^30) in a string.
var powersOf2 = Array.range(31).map(function(i){return 1 << i});
alert("Powers of 2:\n" + delimitNumbers(powersOf2.join("\n")));

One thing you want to keep in mind if you choose to test the delimitNumbers() function with the above code is the fact that you will need to make sure that Array.range() and Array.prototype.map() are correctly defined. I did my test in the ScriptBox which always uses the newest version of jPaq (currently an alpha of v2.0).

Deep Copy of Arrays

With jPaq and many other JavaScript libraries, it is very easy to do a shallow copy of an array. On the other hand, it isn’t as easy to do a deep copy of arrays. For this reason, I plan on replacing the Array.prototype.clone() function with the following:

Array.prototype.clone = function(doDeepCopy) {
    if(doDeepCopy) {
        var encountered = [{
            a : this,
            b : []
        }];

        var item,
            levels = [{a:this, b:encountered[0].b, i:0}],
            level = 0,
            i = 0,
            len = this.length;

        while(i < len) {
            item = levels[level].a[i];
            if(Object.prototype.toString.call(item) === "[object Array]") {
                for(var j = encountered.length - 1; j >= 0; j--) {
                    if(encountered[j].a === item) {
                        levels[level].b.push(encountered[j].b);
                        break;
                    }
                }
                if(j < 0) {
                    encountered.push(j = {
                        a : item,
                        b : []
                    });
                    levels[level].b.push(j.b);
                    levels[level].i = i + 1;
                    levels[++level] = {a:item, b:j.b, i:0};
                    i = -1;
                    len = item.length;
                }
            }
            else {
                levels[level].b.push(item);
            }

            if(++i == len && level > 0) {
                levels.pop();
                i = levels[--level].i;
                len = levels[level].a.length;
            }
        }

        return encountered[0].b;
    }
    else {
        return this.slice(0);
    }
};

The above code can be used to make deep copies of arrays. It is important to note, though, that only sub-arrays are deeply copied, not objects. The reason so much code is used is to even make it possible to make a deep copy of a recursive array structure. The following code exemplifies how to use this function:

// Create a recursive array to prove that the cloning function can handle it.
var arrOriginal = [1,2,3];
arrOriginal.push(arrOriginal);

// Make a shallow copy of the recursive array.
var arrShallowCopy = arrOriginal.clone();

// Prove that the shallow copy isn't the same as a deep copy by showing that
// arrShallowCopy contains arrOriginal.
alert("It is " + (arrShallowCopy[3] === arrOriginal)
    + " that arrShallowCopy contains arrOriginal.");

// Make a deep copy of the recursive array.
var arrDeepCopy = arrOriginal.clone(true);

// Prove that the deep copy really works by showing that the original array is
// not the fourth item in arrDeepCopy but that this new array is.
alert("It is "
    + (arrDeepCopy[3] !== arrOriginal && arrDeepCopy === arrDeepCopy[3])
    + " that arrDeepCopy contains itself and not arrOriginal.");

If you want to use this code right now, there is nothing stopping you. The code doesn’t require any library references and is fully cross-browser compatible. A JSBin example can be found here. It even works in JScript. The only thing that I ask is that you give credit where it is due. :D