February 18, 2020
A overview of arrays in CFML
Comments
(0)
February 18, 2020
A overview of arrays in CFML
I try to bend the internet to my will.
Wizard 34 posts
Followers: 23 people
(0)

Arrays are really useful data structures and since the introduction of arrayMap, arrayReduce and arrayFilter there is very little reason to keep using lists. I thought it might be worth doing a recap of arrays in ColdFusion.

Arrays are useful as they preserve the order of elements. In addition, we can sort them, filter them, map the values, slice them and append to them. Below are some examples of the usage.

OK, let’s start at with the absolute fundamentals:

// create a new array:
a = [];

// create a new with three elements
a = [10,20,30];

Side note: You can also creates arrays using ArrayNew(1) but most of the time you’ll want to be using the newer `[]` syntax

Next up, we want to manipulate the array.

// adding an item to the end of an array (push)
a = [10,20,30];
a.append(40);
expect(a).toBe([10,20,30,40]);

// removing the last item from an array
a = [10,20,30,40];
a.deleteAt(a.len());
expect(a).toBe([10,20,30]);

// remove the first elements from the array
a = [10,20,30,40];
a.deleteAt(1);
expect(a).toBe([20,30,40]);

// add an element to the start of the array
a = [10,20,30,40];
a.prepend(5);
expect(a).toBe([5,10,20,30,40]);

// concatenate two arrays
a = [10,20,30];
a.append([40,50], true);
expect(a).toBe([10,20,30,40,50]);

// insert an element in the middle
a = [10,20,30,40];
a.insertAt(3, 25);
expect(a).toBe([10,20,25,30,40]);

// splice - to remove elements
a = [10,20,30,40];
a.splice(2,2);
expect(a).toBe([10,40]);

// splice - to add element in the middle
a = [10,20,30,40];
a.splice(3,0,[25]);
expect(a).toBe([10,20,25,30,40]);

// splice - to add elements in the middle
a = [10,20,30,40];
a.splice(3,0,[24,26]);
expect(a).toBe([10,20,24,26,30,40]);

// splice - to add elements at the start
a = [10,20,30,40];
a.splice(0,0,[2,4]);
expect(a).toBe([2,4,10,20,30,40]);

// splice - to add elements to the end
a = [10,20,30,40];
a.splice(a.len()+1,0,[42,44]);
expect(a).toBe([10,20,30,40,42,44]);

// splice - to add elements one from the end
a = [10,20,30,40];
a.splice(-1,0,[32,34]);
expect(a).toBe([10,20,30,32,34,40]);

Side note: In the above examples, I’m using member functions (such as `myarray.append(10)`) but I could have used `ArrayAppend(myarray, 10)` instead.

In all of the examples so far we have mutated the array. This can lead to some unexpected side effects, it’s often nice to return a new array instead of changing the existing array. To do this we need to clone the array before we mutate the clone. This can be done in a few ways:

// return new array with value appended
a = [10,20,30];
z = a[:].append(40);
expect(a).toBe([10,20,30]);
expect(z).toBe([10,20,30,40]);

The above example uses the array slice syntax a[:] (introduced in ColdFusion 2018) to create a clone (with the same elements). That can then be chained with an append call to add the new value. As the test expectations show – the original array is unchanged. You could also use arraySlice function.

Another way to get new arrays without mutating the original is to pass them into a function. This is because in ColdFusion (by default) arrays are passed by value.

The following function will return a new array:

function cloneArray(a) {
  return a;
}

x = [10,20,30];
y = cloneArray(x);
y.append(40);
expect(x).toBe([10,20,30]);
expect(y).toBe([10,20,30,40]);

The abovecloneArray function may look a bit odd, but hopefully it demonstrates that arrays are passed by value.

Side note: in ColdFusion you can choose to pass arrays by reference with a setting in Application.cfc, but by default they are passed by value.

Because arrays are passed by value, we can skip all that nasty slice syntax and work with concise functions. For example:

function removeFirstElement(a) {
  return a.deleteAt(1);
}

a = [10,20,30];
z = removeFirstElement(a);
expect(a).toBe([10,20,30]);
expect(z).toBe([20,30]);

I’ve previously blogged about using map, reduce and filter with arrays so won’t recover that ground again. Needless to say they are very useful and powerful features.

I thought I’d end with a couple slightly different examples of how you can use arrays to build ranges. Have you ever needed to get the alphabet? Sure you could type in all 26 characters, but instead you could use arraymap.

placeholders = [];
chars = placeholders.resize(26).map((_, i) => chr(64+i));

expect(chars[1]).toBe("A");
expect(chars[26]).toBe("Z");

You can do this to create any range.

placeholders = [];
chars = placeholders.resize(10).map((_, i) => 10+i);

expect(chars[1]).toBe(11);
expect(chars[10]).toBe(21);

Or how about generating four random hex colours:

placeholders = [];
template = '##000000';
chars = placeholders.resize(4).map(() => {
    return template.replace('0',() => {
        return FormatBaseN((rand()*16), 16);
    }, 'all');
});
0 Comments
Add Comment