When working with arrays in CFML there are times when you want to know the values that set A contains, that are not in set B. There isn’t a native function to do this in CFML (you can do looping etc to do it), as CFML is built on Java, we can take advantage of the underlying removeAll()
Java method.
For example:
function difference(required array a, required array b) { a.removeAll(b); return a; } set1 = [0,2,4,6]; set2 = [0,3,6,9]; // A - B result = difference(set1, set2); writeDump(result); // [2,4] // if we have this.passArrayByReference=true in ACF or using Lucee writeDump(set1); // [2,4]
The result from the function is just what we want. We do have a potentially unwanted side effect though, set1
has been mutated inside the function. By default ColdFusion passes arrays by value, but as of 2016 you can globally enable arrays to be passed by reference. Lucee passes arrays by reference by default.
To solve this problem, there is another Java method we can use to copy the array so that it doesn’t get accidentally mutated.
function difference(required array a, required array b) { var result = a.clone(); result.removeAll(b); return result; } set1 = [0,2,4,6]; set2 = [0,3,6,9]; // A - B result = difference(set1, set2); writeDump(result); // [2,4] // if we have this.passArrayByReference=true in ACF or using Lucee writeDump(set1); // [0,2,4,6]
Now we have a pure function with no nasty side effects to haunt us.
Union of two Arrays
What if want to find the union (the combined unique values) of the two arrays? There is arrayAppend(a, b, true)
which will merge the two arrays, however you can end up with duplicates. For example:
function unionall(required array a, required array b) { a.append(b, true); return a; } set1 = [0,2,4,6]; set2 = [0,3,6]; result = unionall(set1, set2); writeDump(result); // [0,2,4,6,0,3,6] // if we have this.passArrayByReference=true in ACF or using Lucee writeDump(set1); // [0,2,4,6,0,3,6]
As you can see, we have two 0
and two 6
in the resulting array. Another thing to note is that ArrayAppend
will mutate the original array – this may be an unwanted side-effect.
CFML does not have a native method to get the unique values of the merged arrays. To only get the unique values in the union, we can once again take advantage of the underlying Java methods.
function union(a, b) { var result = a.clone(); result.removeAll(b); result.addAll(b); return result; } set1 = [0,2,4,6]; set2 = [0,3,6]; // A + B result = union(set1, set2); writeDump(result); // [2,4,0,3,6] writeDump(set1); // [0,2,4,6]
In the example above, you can see that we do not mutate set1
– we solved that using the Java .clone()
method. .removeAll()
comes in handy to get rid of the duplicates. Then I use .addAll()
to append the second array. The result is that we end up with distinct values in the result returned from the function and set1
is unaffected.
Whilst these methods are handy, you can do this all in CFML if you want, but sometimes it’s useful to drop down to the underlying Java. If you have large arrays then you may find that you’ll be better off using Java’s apache commons libraries and covert to non native CFML datatypes.
The post Union and diff of arrays appeared first on ColdFusion.