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,246 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 »
171 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,246 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,246 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,246 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,246 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 23, 2013 at 6:06 PM
The Girl Who Broke My Heart, And Made Me A Better Person
Good day,ladies and gentle men, my name is Dr AMADI the great spell caster in Africa, i have help so many people for different kind of problems,who say there is no solution to problems on earth, that ... read »
May 23, 2013 at 4:26 PM
ColdFusion QueryAppend( qOne, qTwo )
@Heather, Glad people are still getting value out of this! ... read »
May 23, 2013 at 3:49 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@WebManWalking, I meant the code at the bottom (not the video). I did try to experiment with an intermediary variable, like: value = users.id[ i ]; arrayContains( userIDs, value ); ... but t ... read »
May 23, 2013 at 11:06 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, Are you talking about As Number: YES As String: YES As Java: YES? If so, that's with 3 different ways of referencing the constant 1, not users.id[1]. Query object references(*) are what seem ... read »
May 23, 2013 at 9:55 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dan, According to the CF Admin, I'm running Java "1.6.0_45". As far as the DB column, in the database it's an INT. I'll see if I can dig into what CF sees it as. @WebManWalking, But h ... read »
May 23, 2013 at 9:49 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben, I think the problem is that we're used to loose typing in ColdFusion, like JavaScript. If a value is a number but it's needed in an expression to be a string, noooo problem. I've encountered ... read »
May 23, 2013 at 9:47 AM
ColdFusion QueryAppend( qOne, qTwo )
You rock! Thank you, thank you, thank you!!! ... read »
May 23, 2013 at 5:19 AM
Ask Ben: Print Part Of A Web Page With jQuery
How to print also the background color of table cells and table lines ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools