Learning ColdFusion 9: Delete Array Elements With ArrayDelete()

Posted August 4, 2009 at 10:09 AM by Ben Nadel

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:

  • <!--- 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:

  • <!--- 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:

  • <!--- 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:

  • <!--- 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.


You Might Also Be Interested In:



Reader Comments

Aug 4, 2009 at 10:51 AM // reply »
67 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 »
11,238 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 »
170 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 »
11,238 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 »
11,238 Comments

@Rupesh,

Ahhh, good call! Rock on.


joe
Jul 19, 2010 at 8:41 PM // reply »
1 Comments

nice demo! man what is with ur obsession with girls! every demo has smthing to do with the ladies, not that i mind....


Jul 20, 2010 at 8:52 PM // reply »
11,238 Comments

@Joe,

It's just my version of "foo"/"bar" or "hello world". It's how I keep it a bit more fun.


Oct 15, 2010 at 7:14 PM // reply »
1 Comments

@joe & ben

well at least we have something new, im a little overdosed with foo&bar since college.


Oct 24, 2010 at 1:33 PM // reply »
11,238 Comments

@Nhoel,

Ha ha, thanks :)


Post A Comment

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.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 4:43 AM
How Do You Use The ColdFusion CFParam Tag?
'<cfparam>' or 'isDefined()and <cfset>' performs the same task.Is there any difference? ... read »
May 21, 2013 at 7:46 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
No luck. At least I have uncovered the cause, URLScan 3.1. Here is what I see in the IIS log when a file is over 30mb. 2013-05-21 23:29:05 10.105.45.128 GET /plupload/assets/jquery/jquery-1.8. ... read »
May 21, 2013 at 6:12 PM
Using Plupload For Drag & Drop File Uploads In ColdFusion
Ben, I did not see you after Pete Freitag's Lockdown session at cfObjective but he said that IIS sets file size limits at 30MB by default which just happened to be the threshold for file size when ... read »
May 21, 2013 at 11:51 AM
Ask Ben: Parsing Very Large XML Documents In ColdFusion
Looking at my first ever XML document that I have to parse and put into MS SQL 2000 with CF8. I get it to list the desired Field name, many times over, and have a long list of this field name displa ... read »
May 21, 2013 at 9:25 AM
Turning Off and On Identity Column in SQL Server
you are awesome..i am lucky to get this blog between such a garbage one....Thanks, Prashant ... read »
May 20, 2013 at 4:38 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, Your confusion is well founded, since this is a very confusing features. In fact, it ONLY works if you use array notation. Meaning, that this: arrayToList( query[ "columnName" ] ) ... read »
May 20, 2013 at 4:34 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
I was thinking chicken and the egg, I wouldn't have expected it to work in the valuelist going in I guess. Maybe I just need a beer, long day :) ... read »
May 20, 2013 at 4:29 PM
Using A Dynamic Column Name With ValueList() In ColdFusion
@Dana, That's if you're trying to reference a specific row. In this case, we're trying to reference the entire query column as one cohesive value. So, you are correct that if you wanted to output a ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools