Pick One

Selecting a single element from an array is fairly straightforward. We simply need to know the length of the array and use a couple of Meth methods to pick one of them at random.

Array.prototype.pickOne = function()  {
return this[Math.floor(Math.random() * this.length)];
console.log([1,2,3,4,5].pickOne()); // test

Sometimes though we do not want to just pick at random from the entire array. Sometimes we want to restrict the entries to those that meet some specific criteria and to then pick one from that. This is also trivially easy in JavaScript as JavaScript has a filter method built in that will allow us to extract a subset of an array that meets specific criteria to make a new smaller array and we can then simply apply the same code as above to pick one from that.

For an example let's consider an array of monsters for a game where we want to select monsters from those of a particular level. Suppose we have the following as a part of our array (there would obviously be more monsters and more attributes but that will not change the code we need) and we want to select a level 2 monster at random.

var monsters = [
{type : 'badger', level : 1},
{type : 'ghoul', level : 2},
{type : 'bugbear', level : 3},
{type : 'leprechaun', level : 2},
{type : 'orc', level : 2},
{type : 'lich', level : 5}

\We now add our filter to the pickOne call:

console.log(monsters.filter(function(a) {return a.level === 2;}).pickOne());

This gets us our random selection from just those that are level 2 but it means that we need to call the filter before applying the pickOne. A better solution would be to incorporate the filter into the pickOne so that the filter is applied as a part of that call rather than having to be applied first. Let's start by simply adding the above filter into the pickOne directly.

Array.prototype.pickOne = function()  {
var flt = this.filter(function(a) {return a.level === 2;});
return flt[Math.floor(Math.random() * flt.length)];
console.log(monsters.pickOne()); // test

This works fine but now we are restricted to just those entries that match that single filter condition. Let's make it a bit more flexible by bringing the filter condition back out of the pickOne while leaving the filter itself where it is.

Array.prototype.pickOne = function(f)  {
var flt = this.filter(f);
return flt[Math.floor(Math.random() * flt.length)];

console.log(monsters.pickOne(function(a) {return a.level === 2;})); // test

While this looks a bit like what we had before moving the filter inside of the pickOne it is still an improvement because we don't need to remember to apply the filter method and the code is more readable.

Of course with this pickOne we now always need to provide a callback function to specify the criteria for the filter. Let's make one more change so as to allow the function to work the way it was originally written when no callback function is provided.

Array.prototype.pickOne = function(f)  {
var flt = f ? this.filter(f) : this;
return flt[Math.floor(Math.random() * flt.length)];

So now we can specify a callback function for the filter when we want to specify criteria that the result needs to satisfy or simply call the pickOne without a callback function to simply have it pick an element from the entire array at random.



This article written by Stephen Chapman, Felgall Pty Ltd.

go to top

FaceBook Follow
Twitter Follow