Tag Archives: Array

EcmaScript 6 – Array.of()

A function that is proposed to be added to EcmaScript 6 is Array.of(). This function will be used to create an array of the passed parameters. Since this function is available in some browsers but not in all, here is a block of code which when executed will define it if not already defined:

Array.of = Array.of || function() {
  return Array.prototype.slice.call(arguments);
};

Here are some examples of using the function:

var a = Array.of(1,2,3);     // [1,2,3]
var b = Array.of();          // []
var c = Array.of(undefined); // [undefined]
var d = Array.of(null);      // [null]
var e = Array.of(4);         // [4]

Not the most amusing function, but it is still a step towards EcmaScript 6. 8-)

JavaScript – Range Array Function

A cool function that exists in Python is the range function which actually creates a list of numbers within the specified range. Once again, since I love JavaScript, here a quick imitation of this function:

/**
 * Creates a range of numbers in an array, starting at a specified number and
 * ending before a different specified number.
 * @param {number} start  Indicates what number should be used as the first
 *     number in the returned array.  If this is the only number argument
 *     supplied, this will be used as the edge and 0 will be used as the start.
 * @param {number=} edge  Indicates the first number that should not appear in
 *     the range of numbers.  If this number preceeds the start in the range
 *     (taking into account the step), an empty array will be returned.  If not
 *     specified and not inferred this defaults to 0.
 * @param {number=} step  Indicates the difference between one number and the
 *     subsequent number placed in the returned array.  If not specified this
 *     defaults to 1.
 * @return {!Array.<number>}  Array of numbers in the specified range.
 */
function range(start, edge, step) {
  // If only one number was passed in make it the edge and 0 the start.
  if (arguments.length == 1) {
    edge = start;
    start = 0;
  }

  // Validate the edge and step numbers.
  edge = edge || 0;
  step = step || 1;

  // Create the array of numbers, stopping befor the edge.
  for (var ret = []; (edge - start) * step > 0; start += step) {
    ret.push(start);
  }
  return ret;
}

Of course, this is probably not a complete imitation, but as you can see it gets the job done in most cases:

range(10)
// [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

range(65, 69)
// [65, 66, 67, 68]

range(10, -10.1, -5)
// [10, 5, 0, -5, -10]

range(10, 1)
// []

If you want to use the function code, knock yourself out. 8-)

JavaScript – Better Array Builder

Yesterday I wrote this post about a way to loosely imitate having array comprehensions in JavaScript. After thinking about it a bit more, I thought it would be best to change the function to be more like this:

/**
 * @license Array Builder v2 - By Chris West - MIT License
 * Builds an array either from another array or an object using the values.
 * @param {Array|Object|number} obj  If an array or object is given all of its
 *     items will be traversed.  If a number is given, an array with that length
 *     will be created and then traversed.
 * @param {string|Function|undefined} expression  Optional function or function
 *     expression that if the filter passes will be executed and the returned
 *     value will be placed in the array to be returned by this function.  If a
 *     string is specified, the context object (this) will be obj, the value
 *     will be $value and the key will be $key.  If a function is specified, the
 *     context object (this) will be obj, the key will be the first parameter
 *     and the value the second parameter.  If not specified and obj is number
 *     the value to be added to the returned array will be the key.  If not
 *     specified and obj is not a number, the value to be added to the returned
 *     array will be the value found.
 * @param {string|Function|undefined} optFilter  Optional function or function
 *     expression that will be evaluated for each value and only if a true-ish
 *     value results will the expression be evaluated and the resulting value
 *     added to the built array.  If a string is specified, the context object
 *     (this) will be obj, the value will be $value and the key will be $key.
 *     If a function is specified, the context object (this) will be obj, the
 *     key will be the first parameter and the value the second parameter.
 * @return {!Array}  The array built from the values returned from expression.
 */
var buildArray = (function(toString, undefined) {
  // Internal function which checks the type of an object or primitive
  // (excluding null and undefined).
  function typeIs(obj, typeName) {
    return toString.call(obj).slice(8, -1) == typeName;
  }

  return function(obj, expression, optFilter) {
    // If a number is passed instead of an array or object, create a blank array
    // with that length.
    var objWasNumber = typeIs(obj, 'Number');
    if (objWasNumber) {
        obj = new Array(obj);
    }

    // Make sure the expression is a function.
    if (expression == undefined) {
      expression = objWasNumber ? '$key' : '$value';
    }
    if (typeIs(expression, 'String')) {
      expression = new Function('$value', '$key', 'return ' + expression);
    }

    // If given make sure the filter is a function.
    if (optFilter && typeIs(optFilter, 'String')) {
      optFilter = new Function('$value', '$key', 'return ' + optFilter);
    }

    // This is called for each item in obj and is used to execute the filter (if
    // given) and then add the processed value to the array to be returned.
    function process(key) {
      var value = obj[key];
      if (!optFilter || optFilter.call(obj, value, key)) {
        ret.push(expression.call(obj, value, key));
      }
    }

    // Create the array, build it out, and return it.
    var ret = [];
    if (typeIs(obj, 'Array')) {
      for (var i = 0, len = obj.length; i < len; i++) {
        process(i);
      }
    }
    else {
      for (var key in obj) {
        process(key);
      }
    }
    return ret;
  };
})({}.toString);

Reasons for the Change

  • I wanted the ability to specify a number as the first parameter which would in turn create an array of that length and then process the array.
    buildArray(26, 'String.fromCharCode($key + 65)')
    // Returns array of the letters in the alphabet capitalized.
    
  • I wanted to remove the declaration of a variable which will be used to specify the name of the value.
  • I wanted the key to also be passed into the expression and filter functions.
    buildArray({ firstName: 'Chris', lastName: 'West' }, '$key')
    // ['firstName', 'lastName'] - Not necessarily in this order.
    
  • I wanted to be able to reference the object or array being examined.
    buildArray(['A', 'B', 'C', 'D', 'E'], 'this[this.length - $key - 1]')
    // ['E', 'D', 'C', 'B', 'A']
    
  • I wanted a way to mimic this call in python: range(10).
    buildArray(10)
    // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    

In conclusion there are many advantages to making these changes to the buildArray function. Of course, it still falls short of Python list comprehensions and true array comprehensions, but in the absence of such elegance we must resort to hacks. 8-)

JavaScript – Pseudo Array Comprehensions

In my job I have recently switched over to primarily coding in Python and I am loving the change. One thing that I find interesting is list comprehensions. Still, since my first love is JavaScript, I wanted to be able to do something similar in JavaScript and had remembered coming across its likeness in the language (version 1.7). Unfortunately, it doesn’t seem like this is going to be globally supported very soon so below is an alternative:

/**
 * @license Array Builder - By Chris West - MIT License
 * Builds an array either from another array or an object using the values.
 * @param {!Array|!Object} obj  Array or object to be traversed and whose values
 *     will be transformed and possibly added to the returned array.
 * @param {string} varName  The name of the value as it can appear in the
 *     expression and the optFilter.
 * @param {string} expression  The JavaScript expression that will be evaluated
 *     and possibly placed in the array to be returned by this function.
 * @param {string=} optFilter  Optional filter expression that will be evaluated
 *     will be evaluated for each value and only if a truish value results will
 *     the expression be evaluated and the resulting value added to the built
 *     array.
 * @return {!Array}  The array built from the passed array or object.
 */
var buildArray = (function(hasOwnProperty, toString) {
  return function(obj, varName, expression, optFilter) {
    expression = new Function(varName, 'return ' + expression);
    if (optFilter) {
      optFilter = new Function(varName, 'return ' + optFilter);
    }
    
    var ret = [];
    
    function process(key, obj) {
      var value = obj[key];
      if (!optFilter || optFilter.call(obj, value)) {
        ret.push(expression.call(obj, value));
      }
    }
    
    if (toString.call(obj) == '[object Array]') {
      for (var i = 0, len = obj.length; i < len; i++) {
        process(i, obj);
      }
    }
    else {
      for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) {
          process(key, obj);
        }
      }
    }
    
    return ret;
  };
})({}.hasOwnProperty, {}.toString);

As you can see I have already annotated the above function, but here is an example of using it:

buildArray([1,2,3,4,5], 'x', 'x*x');
// Result:  [1, 4, 9, 16, 25]

buildArray({a:'A', b:'B', c:'C'}, 'c', 'c');
// Result:  ['A', 'B', 'C']

buildArray([1,2,3,4,5], 'i', 'String.fromCharCode(64+i)', 'i%2');
// Result:  ['A', 'C', 'E']

Also, if you are wondering why I named this function buildArray it is because this idea of comprehension lists (or JavaScript comprehension arrays) is derived from set-builder notation in mathematics. If you need, feel free to use this function in your code. 8-)

JavaScript – Weighted Randomization

Today I worked on a project which involved weighted randomization. In other words, I had to randomly choose an item from an array of weighted items. The items that were assigned a higher weight were to be more likely to be picked. The following is a JavaScript function that accomplishes just that:

/**
 * Takes an array of items and an array of the corresponding weights and picks
 * one of the items.  The items with the higher weights are more likely to be
 * picked.
 * @param {!Array} items  An array of items to choose from.
 * @param {!Array.<number>} weights  An array of non-negative integers with each
 *     number representing the likelihood of the number getting picked.
 * @return {*}  Returns one of the items from the array as long as at least one
 *     of the weights was a positive integer.  Otherwise whatever is at
 *     items[-1] will be returned (this usually means undefined is returned).
 */
function pickUsingWeights(items, weights) {
  var total = 0;
  var ranges = weights.slice(0);
  for(var i = 0, len = weights.length; i < len; i++) {
    ranges[i] = [total, total += ranges[i]];
  }
  var randomNumber = parseInt(Math.random() * total);
  for(;randomNumber < ranges[--i][0];);
  return items[i];
}

Example

In my opinion, one of the best ways to understand how to use JavaScript (and other language for that matter) is by example, so here’s one:

// Prizes and the corresponding weights.
var prizes = ['PS4', 'DVD Player', 'Kit-Kat Bar', 'Nothing'];
var weights = [1, 2, 3, 94];

// Populate the prizesGiven object with zeroes for each prize.
var prizesGiven = {};
for(var i = 0; i < prizes.length; i++) {
  prizesGiven[prizes[i]] = 0;
}

// Try using the pickUsingWeights function 1000 times to see
// how well the weighted randomization works.
var ATTEMPTS = 10000;
for(var i = 0; i < ATTEMPTS; i++) {
  prizesGiven[pickUsingWeights(prizes, weights)]++;
}

// Show the results.
var msg = 'The results are as follows:';
for(var i = 0; i < prizes.length; i++) {
  msg += '\r\n- ' + prizes[i] + ' was given out '
      + (100 * prizesGiven[prizes[i]] / ATTEMPTS).toFixed(2)
      + '% of the time.';
}
alert(msg);

You can click here to see the result of running the two preceeding blocks of code. As you can see, the percentages are close to the actual weights specified.

Function Description

This pickUsingWeights function takes an array of items and an array of the corresponding weights and picks one of the items. The most likely items to be picked are those with the higher weights. Any item with a weight of zero has no chance of being picked.

Parameters

  1. items {Array}:
    An array of items to choose from.
  2. weights {Array}:
    An array of non-negative integers with each number representing the likelihood of the corresponding item getting picked.

Returns

Returns one of the items from the items array as long as at least one of the weights was a positive integer. Otherwise whatever is at items[-1] will be returned (this usually means undefined is returned).

Final Notes

If you are working on a project which involves picking items which are weighted feel free to use this function. 8)

JavaScript – Object Property Iterator

One common thing that I end up doing, for work and person projects, when writing JavaScript is iterating over all of the properties of an object that I create. Since this task is quite common, I often wrote a each or forEach function for each project. In my most recent project though I decided that it would be cool to not only publish the function so that I and others can easily find and use it but also to add in the option of returning the property names. Here is the function that I came up with:

/**
 * @license Copyright 2013 - Chris West - MIT Licensed
 */
(function(hasOwnProperty) {
  /**
   * Iterates over all of the properties of the specified object and returns an
   * array of their names.
   * @param {!Object} obj  The object whose properties will be iterated over.
   * @param {function(string, *, !Object):*=} fnCallback  Optional function
   *     callback which, if specified, will be called for each property found.
   *     The parameters passed will be the name of the property, the value of
   *     the property and the object.
   * @return {!Array.<string>}  Returns an array of the names of the properties
   *     found.  If the fnCallback was specified, the only property names that
   *     will be returned will be those for which the fnCallback function
   *     returned a true-ish value.
   */
  eachProperty = function(obj, fnCallback) {
    var ret = [];
    for(var name in obj) {
      if(hasOwnProperty.call(obj, name) && (!fnCallback || fnCallback(name, obj[name], obj))) {
        ret.push(name);
      }
    }
    return ret;
  };
})(({}).hasOwnProperty);

Example

Here is an example of how the above function could be used:

var person = {
  name: 'Chris West',
  gender: 'male',
  age: 25
};

var personProperties = eachProperty(person);
alert('This person has the following properties:  '
  + personProperties.join(', '));
eachProperty(person, function(name, value) {
  alert('My ' + name + ' is ' + value + '.');
});

The following messages will be printed from the above example, each in a separate alert box:

  1. This person has the following properties: name, gender, age
  2. My name is Chris West.
  3. My gender is male.
  4. My age is 25.

It is important to note that depending on the JavaScript engine, the ordering of the property names may vary within the returned array and when the callback is called.

Description

This function iterates over all of the properties of the specified object. This function can both act like the Object.keys and an iterator function of all properties specifically defined for the given object (not prototype defined values).

Parameters

  1. obj {Object}:
    The object whose properties will be iterated over.
  2. fnCallback {Function}:
    Optional function which, if specified will be called for each property found. The parameters passed will be the name of the property, the value of the property and the object.

Returns

Returns an array of the names of the properties found. If the fnCallback was specified, the only property names that will be returned will be those for which the fnCallback function returned a true-ish value.

Final Notes

In summary, this eachProperty function can prove to be very useful. In fact, as I always say with all useful functions, if and when the next version jPaq comes out, I will make sure that this function is included. Until then, please feel free to use this code in your own projects. ;)

JavaScript – Comparing & Sorting Strings with Numbers

Well before I had this site, I created a program which needed to order file names such as the following:

Episode 20 - There's More Than One of Everything.mp4
Episode 4 - The Arrival.mp4
Episode 7 - In Which We Meet Mr. Jones.mp4
Episode 15 - Inner Child.mp4
Episode 6 - The Cure.mp4
Episode 3 - The Ghost Network.mp4

Unfortunately, if you just use the normal {Array}.sort() without a callback function, the following will be the resulting order of the file names:

Episode 15 - Inner Child.mp4
Episode 20 - There's More Than One of Everything.mp4
Episode 3 - The Ghost Network.mp4
Episode 4 - The Arrival.mp4
Episode 6 - The Cure.mp4
Episode 7 - In Which We Meet Mr. Jones.mp4

As you can see, the 15th episode comes before the 3rd episode after being sorted but in most cases we would want the order to be as follows:

Episode 3 - The Ghost Network.mp4
Episode 4 - The Arrival.mp4
Episode 6 - The Cure.mp4
Episode 7 - In Which We Meet Mr. Jones.mp4
Episode 15 - Inner Child.mp4
Episode 20 - There's More Than One of Everything.mp4

For this reason, I wrote the cmpStringsWithNumbers function which takes two strings and compares them by separating the substrings with numbers from the substrings without numbers:

(function() {
  // Regular expression to separate the digit string from the non-digit strings.
  var reParts = /\d+|\D+/g;

  // Regular expression to test if the string has a digit.
  var reDigit = /\d/;

  // Add cmpStringsWithNumbers to the global namespace.  This function takes to
  // strings and compares them, returning -1 if `a` comes before `b`, 0 if `a`
  // and `b` are equal, and 1 if `a` comes after `b`.
  cmpStringsWithNumbers = function(a, b) {
    // Get rid of casing issues.
    a = a.toUpperCase();
    b = b.toUpperCase();

    // Separates the strings into substrings that have only digits and those
    // that have no digits.
    var aParts = a.match(reParts);
    var bParts = b.match(reParts);

    // Used to determine if aPart and bPart are digits.
    var isDigitPart;

    // If `a` and `b` are strings with substring parts that match...
    if(aParts && bParts &&
        (isDigitPart = reDigit.test(aParts[0])) == reDigit.test(bParts[0])) {
      // Loop through each substring part to compare the overall strings.
      var len = Math.min(aParts.length, bParts.length);
      for(var i = 0; i < len; i++) {
        var aPart = aParts[i];
        var bPart = bParts[i];

        // If comparing digits, convert them to numbers (assuming base 10).
        if(isDigitPart) {
          aPart = parseInt(aPart, 10);
          bPart = parseInt(bPart, 10);
        }

        // If the substrings aren't equal, return either -1 or 1.
        if(aPart != bPart) {
          return aPart < bPart ? -1 : 1;
        }

        // Toggle the value of isDigitPart since the parts will alternate.
        isDigitPart = !isDigitPart;
      }
    }

    // Use normal comparison.
    return (a >= b) - (a <= b);
  };
})();

Here is an example of how one could use the above function:

var fileNames = [
  "Episode 20 - There's More Than One of Everything.mp4",
  "Episode 4 - The Arrival.mp4",
  "Episode 7 - In Which We Meet Mr. Jones.mp4",
  "Episode 15 - Inner Child.mp4",
  "Episode 6 - The Cure.mp4",
  "Episode 3 - The Ghost Network.mp4"
].sort(cmpStringsWithNumbers);

alert(fileNames.join('\n'));

After the above two code blogs run, the following would be alerted to the user:

Episode 3 - The Ghost Network.mp4
Episode 4 - The Arrival.mp4
Episode 6 - The Cure.mp4
Episode 7 - In Which We Meet Mr. Jones.mp4
Episode 15 - Inner Child.mp4
Episode 20 - There's More Than One of Everything.mp4

One thing that is important to note is that this comparison function is case-insensitive. This function is pretty well documented so if you have a need for it in your JScript, HTA 8) , or JavaScript file, feel free to use it.

JavaScript – String.prototype.matchAll(regexp)

One of the nice things that many people don’t know about JavaScript String replace() function is the fact that the second parameter can either be a string or a callback function. This callback function receives the entire matched substring, each parenthesized group (if not found the empty string is passed), the index of the match within the original string, and the original string. You can actually get these values using the String match() function, but this doesn’t work for retrieving these values for each instance of a globally matched regular expression. In this case, one could use the following code to define a matchAll() function:

String.prototype.matchAll = function(regexp) {
  var matches = [];
  this.replace(regexp, function() {
    var arr = ([]).slice.call(arguments, 0);
    var extras = arr.splice(-2);
    arr.index = extras[0];
    arr.input = extras[1];
    matches.push(arr);
  });
  return matches.length ? matches : null;
};

If a global regular expression is passed to the function defined above, an array of arrays similar to those that come from the native match() will be returned. As occurs with the native match() function, each sub-array will have an index property and an input property. The index property indicates the position where this particular match began in the original string. The input property indicates the string that the matches were found in.

The following is an example of running this function:

var str = 'Hello world!!!';
var regexp = /(\w+)\W*/g;
console.log(str.matchAll(regexp));

An array containing two arrays will be generated:

[
  {
    0: "Hello ",
    1: "Hello"
    index: 0,
    input: "Hello world!!!"
  },
  {
    0: "world!!!",
    1: "world"
    index: 6,
    input: "Hello world!!!"
  }
]

Even though the sub-arrays above are really object literals, the arrays that come back from this matchAll() function will be true arrays with those two properties (index and input) set for each. Hopefully this helps. 8)

POW Answer – Appending = Adding Squares

This post gives the answer to last week’s Problem of the Week.

First of all, I have to admit that this problem actually came from the Quicker Maths blog. This blog actually pulled the problem from IBM’s Ponder this section.

First of all, in order to write the equation algebraicly, we could express the relationship as follows:
x2 + y2 = x + y × 1000

Unfortunately, the difficulty with solving the problem with just pencil and paper is the fact that we have to solve for the variables when they are both integers. For this reason, let’s do it with a programming language such as Python:

arr = []
for x in range(1000, 10000):
    for y in range(x, 10000):
        sum = x * x + y * y
        if sum == x * 10000 + y:
            arr.append("x = {0}, y = {1} => {2}".format(x, y, sum))
        elif sum == y * 10000 + x:
            arr.append("x = {0}, y = {1} => {2}".format(y, x, sum))

print("x * x + y * y = x * 10000 + y where:")
print("\n".join(arr))

Using this code will result in the following being printed out:

x * x + y * y = x * 10000 + y where:
x = 9412, y = 2353 => 94122353

As you can see, this was the brute-force way of solving this problem, but sometimes the brute-force way is the fastest way to come to the correct answer. 8)

JavaScript – Sort An Array of Type

One thing that is not extremely obvious in JavaScript is how you sort arrays. Yes, of course I know that arrays have the native sort() function, but did you know that the following will incorrectly sort the array of numbers:

var arr = [1,2,3,10,101,1000];
alert(arr.sort());  // 1,10,1000,101,2,3

How crazy is that? Even though the array is in the correct order, the sort() function reorders it incorrectly. Why does it do this? It orders it this way because it actually sorts all elements within the array as if they are strings, not numbers.

Comparison Function Needed

In order to properly sort an array, you need to make sure you have a comparison function for comparing the elements within the array. The function must take two parameters which can be any two elements from the array. The function should return a negative number if the first parameter should appear before the second parameter. The function should return a 0 if the two parameters are equivalent. The function should return a positive number if the first parameter should appear after the second. The following is a comparison function that works for numbers:

function cmpNumbers(a, b) {
  return a - b;
}
[code language="javascript"]

To use this function to allow for sorting arrays of numbers, you can do the following to incorporate your new comparison function in the sort:
[code language="javascript"]
var arr = [1,10,1000,101,2,3];
arr.sort(cmpNumbers);
alert(arr);  // 1,2,3,10,101,1000

Imagine that you have an array of Person objects that you want to sort. If you want sort the Person objects by last names, you can use code such as the following:

// Definition for the Person object
function Person(fullName) {
  this.fullName = fullName;
  this.firstName = fullName.split(" ")[0];
  this.lastName = fullName.split(" ").slice(-1)[0];
}
Person.prototype.toString = function() {
  return this.fullName;
};

// for sorting last_name, first_name
function cmpPersonLastFirst(a, b) {
  return a.lastName != b.lastName
    ? a.lastName < b.lastName ? -1 : 1
    : (a.firstName != b.firstName
      ? a.firstName < b.firstName ? -1 : 1
      : 0
    );
}

// The array of people to be sorted
var people = [];
people.push(new Person("Michael Villegas"));
people.push(new Person("Vanessa Garcia"));
people.push(new Person("Jonathan Villegas"));
people.push(new Person("Anton Sheehan"));
people.push(new Person("Melissa Johnson"));
people.push(new Person("Sarah Rush"));
people.push(new Person("Sarah Baranski"));

// Sort the array of people (last name, first name)
people.sort(cmpPersonLastFirst);

// Show the people in order of last name
alert("This is the array of sorted people:\n -"
      + people.join("\n- "));

Here is what will be outputted:

This is the array of sorted people:
 -Sarah Baranski
- Vanessa Garcia
- Melissa Johnson
- Sarah Rush
- Anton Sheehan
- Jonathan Villegas
- Michael Villegas

Cool stuff, right? Now, hopefully you can see with these two examples how you can optionally supply a comparison function to the sort() function in order to sort an array of any type of object.