Learning ColdFusion 9: Delete Array Elements With ArrayDelete()

Posted August 4, 2009 at 10:09 AM

Tags: ColdFusion

A little while ago, I blogged about ColdFusion 9's new ArrayFind() and ArrayContains() methods. ColdFusion 9 also has a similar method for deleting elements from an array: ArrayDelete(). Like ArrayFind() and ArrayContains(), ArrayDelete() takes an array and a target value to delete (rather than a target index as is used in ArrayDeleteAt()). To explore this, I set up a simple demo:

 Launch code in new window » Download code as text file »

  • <!--- Create an array with simple values. --->
  • <cfset girls = [
  • "Sarah",
  • "Molly",
  • "Sarah",
  • "Joanna",
  • "Carolyn",
  • "Sarah"
  • ] />
  •  
  • <!--- Delete "Sarah" from the array. --->
  • <cfset arrayDelete( girls, "Sarah" ) />
  •  
  • <!--- Output the resultant array. --->
  • <cfdump
  • var="#girls#"
  • label="Girls (minus Sarah)"
  • />

Here, we are building an array of values and then deleting one of them. Notice that the value that we are deleting, "Sarah," appears multiple times within the original array. After we call ArrayDelete() on the array with the target value, "Sarah," we get the following CFDump output:

 
 
 
 
 
 
ColdFusion 9's New ArrayDelete() Function Lets You Delete A Given Value From An Array Without Knowing Its Index. 
 
 
 

Notice that only one of the three instances of "Sarah" were removed from the array. As it turns out, ArrayDelete() only deletes the first instance that it finds, leaving the last two intact.

Since both ArrayFind() and ArrayContains() work with complex values, I assumed that ArrayDelete() would as well; but, rather than assuming now and being wrong later, I figured I should run at least one test with complex data:

 Launch code in new window » Download code as text file »

  • <!--- Create an array with complex values. --->
  • <cfset girls = [
  • {
  • name = "Sarah",
  • isHot = true
  • },
  • {
  • name = "Carolyn",
  • isHot = true
  • },
  • {
  • name = "Sarah",
  • isHot = true
  • }
  • ] />
  •  
  • <!--- Delete "Sarah" from the array. --->
  • <cfset arrayDelete(
  • girls,
  • {
  • name = "Sarah",
  • isHot = true
  • }
  • ) />
  •  
  • <!--- Output the resultant array. --->
  • <cfdump
  • var="#girls#"
  • label="Girls (minus Sarah)"
  • />

Here, you can see rather than having simple girl names, I am creating complex girl objects. And, rather than passing in a simple name to the ArrayDelete() function, I am passing in a struct. When we run this code, we get the expected CFDump output:

 
 
 
 
 
 
ColdFusion 9's new ArrayDelete() Method Also Works With Complex Values As Well As Simple Values. 
 
 
 

Just as we would expect based on the first example, only the first instance of the Sarah girl object was deleted.

But what do we do if we want to delete all of the instances of a given value from our array? One option would be use ColdFusion 9's new ArrayFind() and ArrayDelete() methods in a conditional loop:

 Launch code in new window » Download code as text file »

  • <!--- Create an array with simple values. --->
  • <cfset girls = [
  • "Sarah",
  • "Molly",
  • "Sarah",
  • "Joanna",
  • "Carolyn",
  • "Sarah"
  • ] />
  •  
  • <!---
  • Keep deleting from the array until no matching
  • values can be found.
  • --->
  • <cfloop condition="arrayFind( girls, 'Sarah' )">
  •  
  • <!--- Delete the given value. --->
  • <cfset arrayDelete( girls, "Sarah" ) />
  •  
  • </cfloop>
  •  
  • <!--- Output the resultant array. --->
  • <cfdump
  • var="#girls#"
  • label="Girls (ArrayFind() Condition)"
  • />

As you can see in the code, we keep looping while ArrayFind() returns a non-zero index. For every instance that ArrayFind() locates, we are then deleting it with ArrayDelete(). And, when we run this code, we get the following CFDump output:

 
 
 
 
 
 
Using CFLoop And A Condition, We Can Delete All Values With ArrayDelete(). 
 
 
 

This time, all three instances of "Sarah" were successfully removed from our girls array.

The above conditional CFLoop works, but it has a fundamental performance flaw: it searches the array twice as many times as it really needs to. The ArrayFind() method in the Condition searches the array to locate the given value; then, within loop body, the ArrayDelete() method searches the array to find the target value again (in order to delete it). Ideally, what we really want to do is capture the index returned by ArrayFind() and use it to delete the specific value within the array:

 Launch code in new window » Download code as text file »

  • <!--- Create an array with simple values. --->
  • <cfset girls = [
  • "Sarah",
  • "Molly",
  • "Sarah",
  • "Joanna",
  • "Carolyn",
  • "Sarah"
  • ] />
  •  
  • <!---
  • Keep deleting from the array until no matching
  • values can be found. This time, however, rather than
  • using ArrayDelete() to search / delete the given
  • record, we are going to store the match of the target
  • element returned from ArrayFind() and then delete it
  • exactly using ArrayDeleteAt().
  • --->
  • <cfloop condition="targetIndex = arrayFind( girls, 'Sarah' )">
  •  
  • <!--- Delete the specific value. --->
  • <cfset arrayDeleteAt( girls, targetIndex ) />
  •  
  • </cfloop>
  •  
  • <!--- Output the resultant array. --->
  • <cfdump
  • var="#girls#"
  • label="Girls (ArrayDeleteAt())"
  • />

With this new code, we are only searching the array once with ArrayFind() and then deleting the target index with the old-school method, ArrayDeleteAt(). And, when we run this code, we get the same result with hypothetically better performance:

 
 
 
 
 
 
ArrayDeleteAt() Will Give Us Better Performance Than ArrayDelete() If We Are Deleting Multiple Instances Of A Value. 
 
 
 

ArrayDelete() is one of the many minor but excellent updates that ColdFusion 9 brings to the table. However, it seems that this new function will be most useful when deleting a single value from a known array; once you have to delete more than the first instance of a value, you're going to get better performance if you fall back on the older method, ArrayDeleteAt(), which won't require a re-searching of the array.

Download Code Snippet ZIP File

Post Comment  |  Ask Ben  |  Other Searches  |  Print Page


You Might Also Be Interested In:




Reader Comments

Aug 4, 2009 at 10:51 AM // reply »
44 Comments

The repeated calls to arrayFind() in the last example mean that it's going to start from the beginning to search each time. But, at least, you aren't doing it twice for each iteration, as you would be if you used arrayDelete(), too.

Even that last solution falls short of manually looping over the array and inspecting each value once. (Just remember to do it in reverse.)

So ... yeah. I fail to see the real-world utility of the arrayDelete() function.


Aug 4, 2009 at 10:55 AM // reply »
7,572 Comments

@Rick,

Ahh, very true - looping over it backwards and deleting would be the best of all possible worlds. Agreed though, unless you are deleting a single value, I find this to be less usable.


Aug 4, 2009 at 10:58 AM // reply »
124 Comments

It seems like ArrayDelete() should have an optional 3rd argument for selecting whether you want to remove all instances or only the first (like the removeXXX() functions have.)


Aug 4, 2009 at 11:07 AM // reply »
7,572 Comments

@Dan,

Agreeed - that would be sweet!


Aug 4, 2009 at 11:32 AM // reply »
2 Comments

This does the same thing in removing duplicates correct? The only limitation is working with one-dim arrays.

hashSet = CreateObject("java","java.util.LinkedHashSet").init(girls);
girl s= hashSet.toArray();

If arraydelete() is faster for two-dim arrays, that is where I would find it most useful. It beats nested loops.


Aug 4, 2009 at 2:04 PM // reply »
25 Comments

arrayDelete(myArray, "Sarah") functionality has been available since the Java conversion via myArray.remove("Sarah"). And be careful with the array->Set->array conversion - that removes any ordering in the array.

If you care about ordering you'll need to use the Set manually (in psuedo-code):

s = new java.util.HashSet();
for (i = arrayLen(myArray); i >= 1; i -= 1) {
if (NOT s.add(myArray[i])) {
// it was already in there, so delete it
arrayDeleteAt(myArray, i);
}
}


Aug 4, 2009 at 2:12 PM // reply »
25 Comments

ArrayDelete returns a boolean value specifying whether the deletion was successful. It will return false if and only if the element was not found. So you can run ArrayDelete in a loop until the method returns false. That way you don't need to do a find and then delete in a loop.


Aug 4, 2009 at 2:14 PM // reply »
7,572 Comments

@Rupesh,

Ahhh, good call! Rock on.


Post Comment  |  Ask Ben

Recent Blog Comments
Mar 20, 2010 at 12:07 PM
Drawing On The iPhone Canvas With jQuery And ColdFusion
Simply awesome. Saved my day. ... read »
Mar 20, 2010 at 9:00 AM
Building A Fixed-Position Bottom Menu Bar (ala FaceBook)
I would like to say thx for an easy way to create a bottom bar. I do have a ?. Is it possible to center the bar if i want to resize it to ex 85%. Regards Offenbach ... read »
Mar 19, 2010 at 7:26 PM
MySQL 3/4 - com.mysql.jdbc.Driver And allowMultiQueries=true
Thank you very much for this post. Adding allowMultiQueries="true" in context.xml didn't help until I added it to url as allowMultiQueries=true Good idea is to use prepared statements and it will he ... read »
Jim
Mar 19, 2010 at 4:49 PM
Nobody Puts Baby In The Corner!
Wow. This is like suddenly finding a support group for your secret shame. I'm not alone! I always liked this movie, even though it is extremely cheesy. I just wish Jennifer Grey hadn't gotten the ... read »
Mar 19, 2010 at 4:47 PM
Application.cfc OnRequest() Method Affects OnError() Arguments
@Jason and @Ben, I've been doing some CF9 refactoring on our systems and noticed an odd occurrence with onError as well. Found a way to work around my problem, but what I saw was... Background: Our ... read »
Jim
Mar 19, 2010 at 4:44 PM
Shoot 'Em Up Starring Clive Owen And Paul Giamatti
I actually enjoyed this movie quite a lot. It was different, certainly, but I think they were going for more of a Quentin Tarentino-"wow, that was weird"-vibe than an actual spoof. Once I realize ... read »
Mar 19, 2010 at 4:34 PM
An Intensive Exploration Of jQuery With Ben Nadel (Video Presentation)
Hey I guess the video is down. Is there anyway you can upload to youtube or vimeo or some other service? Greatly appreciated. ... read »
Mar 19, 2010 at 4:24 PM
ColdFusion CFPOP - My First Look
@Ben Thanks for the follow up! The root of the problem had to do with being able to trace bounced emails to specific records in a DB table. Let's say you run an email campaign and you get 1,000 bou ... read »