« Safely Selecting the Last Inserted ID, Part II | Main | Google's Been Busy »
November 16, 2004
Chopping Off the End of a List
I'm sure there are tons of these functions around, but I decided to write my own. The listChop function chops a list down to the specified size. Use it like this:
<cfset myList = "a,b,c,d,e"/>
<!--- Chop this list down to 3 elements. --->
<cfset myList = listChop(myList, 3[, delimiter])/>
Here's the function:
<cffunction name="listChop" returnType="string" output="no" >
<cfargument name="targetList" type="string" required="true"/>
<cfargument name="amountToKeep" type="numeric" required="true"/>
<cfargument name="delimiter" type="string" required="false" default=","/>
<cfset var listSize = listLen(arguments.targetList, arguments.delimiter)/>
<cfset var i = 0/>
<cfif arguments.amountToKeep lt 0 or listSize - arguments.amountToKeep le 0>
<cfreturn arguments.targetList/>
</cfif>
<cfloop from="#arguments.amountToKeep+1#" to="#listSize#" index="i">
<cfset arguments.targetList = listDeleteAt(arguments.targetList,
arguments.amountToKeep+1,
arguments.delimiter)/>
</cfloop>
<cfreturn arguments.targetList/>
</cffunction>
I'm using it in a pretty big application I'm writing, so let me know if you see any bugs.
Posted by cantrell at November 16, 2004 03:50 PM | References
Related Entries
- CFEclipse and Flex Builder 2: Happy Together
- Making Your ColdFusion and Java Applications More Platform Independent (Part III)
- Why Distinguish Between GETs and POSTs?
- Don't Forget to Scope CFHTTP
- Partial Page Caching with ColdFusion
Comments
You are right:
http://www.cflib.org/udf.cfm?ID=605
I think when you spend time writing your own functions when they already exist, and are readily available in a big library like cflib, you are wasting someone's time, either your own, or (hopefully not), your employers/clients.
It's great to learn by doing, but I think in this case, writing your own function when one was readily available to you was counterproductive.
Posted by: Tim Scaret at November 16, 2004 06:22 PM
It's not that simple, Tim. I usually write my own UDFs and components even though I know there are hundreds available because:
1. I like to know exactly how they work. Rather than download one that's already written and going through it line by line, it's often just as fast to write it myself.
2. When I write my own UDFs and components, I get the API exactly how I want it.
3. I can make my own UDFs and components leaner than generic code meant to work for as many people as possible in as many different circumstances as possible.
4. My UDFs and components often leverage each other and are therefore more modular than generic code one might download.
It's a matter of resources. If I have time, I write my own (usually). If it's something that will take minutes as opposed to days, I write my own (usually). It all depends on the specific case. It's way too simple, however, to say uniformly that not using other people's code is a waste of time.
Posted by: Christian Cantrell at November 16, 2004 06:48 PM
Christian.
You make some good points, sorry if I came off too neg on that post.
Posted by: Tim Scaret at November 16, 2004 06:57 PM
Sadly, it's probably not going to look all that wonderful in the comments, but here's another approach I threw together. Not highly tested and I'm aware that regex is considered slow, but when it's compared to the array deleting elements in a loop, she might fair pretty well
Either way, food for thought.
function test(list,count,delimit) {
var regex = ''; var delim = ','; // var'd statements
if (arraylen(arguments) gt 2)
/*
clean up delim to make sure there isn't any special characters
rather harmless if it's a comma, but a pipe delim (common) would kill it
could even be within it's own udf.
*/
delim = rereplace(delimit,'(\+|\*|\?|\.|\[|\^|\$|\(|\)|\{|\||\\)','\\\1');
/*
regex break down
^ start of list
(.*?#delim#){#count-1#} match all but the last element
(.*?[^#delim#]){1} last element minus the delim
(#delim#.*?)+ the rest of the list
#delim#? incase there is a stray delim at the end
$ end of string
*/
regex = '^((.*?#delim#){#count-1#}(.*?[^#delim#]){1})(#delim#.*?)+#delim#?$';
return rereplace(list,regex,'\1');
}
Posted by: Robby at November 16, 2004 08:36 PM
here is another option that uses two functions: listLeft and arrayLeft. Again, we know the formatting will stink - but hopefully it is enough to be clear:
function ListLeft(list, numElements){
var delimiter=",";
var array = ArrayNew(1);
if (Arraylen(arguments) gt 2) {
delimiter=arguments[3];
}
array = ListToArray(list,delimiter);
array = arrayLeft(array,numElements);
if(isArray(array))
list = ArrayToList(array,delimiter);
else
list = array;
return list;
}
function ArrayLeft(array,numElements){
var tArray= ArrayNew(1);
if (numElements gte arrayLen(array)){
return array;
}
for (i=1; i LTE numElements; i=i+1){
tArray[i] = array[i];
}
return tArray;
}
when dealing with really long lists this seems to be faster. Before I rewrote them as two separate functions I did a little analysis which you can see here:
http://rawlinson.us/blog/index.php?p=160
I also have a bunch of other ones (listRight, arrayRight, listSplitLeft, arraySplitLeft, listDeleteLeft, listDeleteRight, arrayDeleteLeft, arrayDeleteRight if you need/want any of them.
Posted by: Bill Rawlinson at November 16, 2004 11:38 PM
No worries, Tim. All opinions are always welcome!
Posted by: Christian Cantrell at November 17, 2004 10:37 AM
The first response to this post stated that the UDF already existed. (http://www.cflib.org/udf.cfm?ID=605)
I looked at it though, and it chops off a KNOWN number of elements from the end of a list.
The one that was written as the subject of this post reduces a list of unknown length down to a known number of elements - two completely different functions. So this to me is a great example of looking at other people's code, deciding if you can use it or not, or use parts of it, or just what you learned from it to write your own. Getting the CORRECT function into the code is worth your time, your client's time, etc...
Posted by: Alan at December 24, 2004 09:11 AM