Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at Scotch On The Rock (SOTR) 2010 (London) with: Katie Atkinson

Appending One Array To Another With ArrayAppendAll() In ColdFusion

By Ben Nadel on
Tags: ColdFusion

This is just a super quick post about merging or concatenating two arrays in ColdFusion. Currently, the only way to natively join two arrays in ColdFusion is to use arrayAppend(), pushing one value at a time from the incoming array onto the target array. You can use the undocumented Collection method - array.addAll() - which I've done a number of times; but, if you want to keep things completely ColdFusion-friendly, you have to use a ColdFusion user defined function like arrayAppendAll().

To see this UDF in action, we'll create two arrays and then append one to the other:

  • <cffunction
  • name="arrayAppendAll"
  • access="public"
  • returntype="array"
  • output="false"
  • hint="I append (concat) the entire incoming array to the target array.">
  •  
  • <!--- Define arguments. --->
  • <cfargument
  • name="targetArray"
  • type="array"
  • required="true"
  • hint="I am the array being augmented"
  • />
  •  
  • <cfargument
  • name="incomingArray"
  • type="array"
  • required="true"
  • hint="I am the array being added to the target array."
  • />
  •  
  • <!--- Define the local scope. --->
  • <cfset var local = {} />
  •  
  • <!---
  • Loop over the incoming array and add each value to the
  • target array. If we wanted to get *naughty*, we could use
  • the Collection-based interface of the array:
  •  
  • array.addAll( array )
  •  
  • However, to keep things ColdFusion-friendly, we'll perform
  • the array augmentation manually.
  • --->
  • <cfloop
  • index="local.incomingValue"
  • array="#arguments.incomingArray#">
  •  
  • <!--- Append the incoming value. --->
  • <cfset arrayAppend(
  • arguments.targetArray,
  • local.incomingValue
  • ) />
  •  
  • </cfloop>
  •  
  • <!---
  • Since arrays are passed by VALUE in ColdFusion, we have to
  • return the resultant array.
  • --->
  • <cfreturn arguments.targetArray />
  • </cffunction>
  •  
  •  
  •  
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  • <!--- ----------------------------------------------------- --->
  •  
  •  
  •  
  • <!--- Create an array of women. --->
  • <cfset women = [ "Sarah", "Tricia", "Joanna" ] />
  •  
  • <!---
  • Create an incoming array of women that we want to add to
  • the first one.
  • --->
  • <cfset incomingWomen = [ "Katie", "Jill", "Erica" ] />
  •  
  • <!---
  • Add one array to the other.
  •  
  • NOTE: Since ColdFusion arrays are passed by VALUE, we have to
  • overwrite the "women" variable with the resultant array.
  • --->
  • <cfset women = arrayAppendAll( women, incomingWomen ) />
  •  
  • <!--- Output the list of women. --->
  • <cfoutput>
  •  
  • Women: #arrayToList( women, " - " )#
  •  
  • </cfoutput>

As you can see, we're still looping over the incoming array, copying over its values one index at a time; but, since this is now encapsulated in a UDF, it's much easier to do. Running the above code gives us the following output:

Women: Sarah - Tricia - Joanna - Katie - Jill - Erica

As you can see, we were able to concatenate the two arrays.

Since arrays are passed by value in ColdFusion, our UDF cannot work directly on the original array. Instead, arrayAppendAll() has to work on its own copy which it then returns as a result of the function execution. It is then up to the calling context to store that resultant array back into the most appropriate variable.

I'd really like an arrayAppendAll() function (or something similar) to be added to the ColdFusion core language. I find this kind of situation comes up a lot. And, since it's a method of the underlying Collection interface, I have to believe that it would be really easy for the ColdFusion engineers to implement.




Reader Comments

Au contraire sir, if you simply write your udf to accept strings instead of variables you'll be able to inject the resulting array into the calling variables scope and get the result you're looking for.

Reply to this Comment

@David,

That would only work IF you knew the name of the variable referencing the array that is being updated. I suppose you could pass in the "variable path" to the array being augmented.

@Mark,

Agreed; I feel like Adobe has never came out and took a stand on whether or not we *should* use the underlying Java methods. I use them personally, but I'd love to hear a definitive answer.

A while back, I realized that, to some degree, you *have* to use the Java methods on CF objects simply because ColdFusion doesn't allow you to differentiate the two types:

http://www.bennadel.com/blog/1023-ColdFusion-Wants-You-To-Access-The-Underlying-Java-Methods.htm

I also tested this on Vectors as well. Create an instance of a Java Vector and isArray( javaVector ) will return "True".

Since we can't natively differentiate between ColdFusion data structures and Java data structures with "similar" interfaces, it would lead us to the conclusion that ColdFusion wants us to use the underlying Java methods.

Reply to this Comment

You know Ben, CF underlying Java core works better for this. ColdFusion arrays are actually an implementation of java list (java.util.List). So all the java list methods can easily be used with CF. So to merge two arrays (which is essentially what you're doing) use the list.addAll() method.

For instance, you have two arrays:

<cfset women = [ "Sarah", "Tricia", "Joanna" ] />
<cfset incomingWomen = [ "Katie", "Jill", "Erica" ] />

Then all you have to do to merge the arrays is

<cfset women.addAll(incomingWomen ) />

Much simpler and cleaner.

I wish I could take credit for it but its based on a blog entry by Rupesh Kumar of Adobe.

http://coldfused.blogspot.com/2007/01/extend-cf-native-objects-harnessing.html

regards,
larry

Reply to this Comment

@Larry,

Yeah, that .addAll() method is cool (as I mentioned in my first paragraph :P). That said, thanks for the link to Rupesh's blog. Since he's an Adobe ColdFusion engineer, this looks like a pretty official position that we *can* use the Java methods. Rockin :)

Reply to this Comment

Why not use the Java?

1) Well, other coldfusion implementations may not support it (Railo, OpenBD, BD.NET). If you want to be portable across CF runtimes, you're pretty much stuck with plain jane cfml.

2) Adobe might change their API in a future release.Thing is, they could do the same with the CFML. :) That's less likely, but unless they drastically change implementations, I don't see it as a problem.

I've done this with the lists and stuff for years, since the list performance on cf7 and earlier was terrible. cf8 and 9 both improved the situation greatly, so I don't rely on it for list stuff as much anymore.

In fact, I even routinely use undocumented java functions. Typically from within a java library, fronted by a cfc or another facade so other devs don't really have to touch the java.

For example, I use the java jackson library in conjunction with a coldfusion.sql.QueryTable to generate non-messed up json (with the same performance as cf8's native json) and I recently implemented ehcache integration for cf8.

It's been so many years since CF went java, and so many devs are still afraid of it.

Reply to this Comment

Hi Ben,
We can also handle the Array append with the help of ArrayToList() and ListToArray() in easy way.

  • <cfset women = [ "Sarah", "Tricia", "Joanna" ] />
  • <cfset incomingWomen = [ "Katie", "Jill", "Erica" ] />
  • <cfset womenList = ArrayToList(women)>
  • <cfset incomingWomenList = ArrayToList(incomingWomen)>
  • <cfset NewWomenList = ListAppend(womenList,incomingWomenList)>
  • <cfset women = ListToArray(NewWomenList)>
  • <cfoutput>
  • Women: #arrayToList( women, " - " )#
  • </cfoutput>

Reply to this Comment

I've got several versions of CF to deal with so compatibility is paramount for me. This works great, thanks!

Reply to this Comment

@Mark,

Yeah, the Java methods are cool. I've often used them when dipping down into String's replaceFirst() and replaceAll() methods. There's always a chance that something will change; but from what I've read, it seems to be generally held as safe to use these kind of approaches.

@Manoj,

You can definitely do that, so long as all of your array contents are simple values. If you had an array of structs, for example, ColdFusion wouldn't be so happy :)

@Frank,

Good stuff.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.