Utility Function: ListRemove() and ListRemoveNoCase()

I ran into a problem earlier where I needed to remove the elements of one list from another list I could have worked around it in a couple of ways, but I thought that I'd rather have a function to do this for me.

<cffunction name="ListRemove" output="false" returntype="string">
    <cfargument name="string1" type="string" required="true" />
    <cfargument name="string2" type="string" required="true" />
    <cfargument name="scope" type="string" required="false" default="all" />
    <cfargument name="delimiters" type="string" required="false" default="," />

    <cfset var returnValue = "" />
    <cfset var position = 0 />

    <cfif NOT ListFindNoCase("one,all", arguments.scope)>
        <cfthrow errorcode="ListRemove" message="Invalid argument SCOPE. Valid values are ONE and ALL." />
    </cfif>

    <cfloop list="#arguments.string1#" index="value" delimiters="#arguments.delimiters#">
        <cfset position = ListFind(arguments.string2, value, arguments.delimiters) />
        
        <cfif position gt 0 AND arguments.scope eq "one">
            <cfset arguments.string2 = ListDeleteAt(arguments.string2, position) />
        <cfelseif position eq 0>
            <cfset returnValue = ListAppend(returnValue, value, arguments.delimiters) />
        </cfif>
    </cfloop>

    <cfreturn returnValue />
</cffunction>

And that meant that I needed to make the case insensitive version as well.

<cffunction name="ListRemoveNoCase" output="false" returntype="string">
    <cfargument name="string1" type="string" required="true" />
    <cfargument name="string2" type="string" required="true" />
    <cfargument name="scope" type="string" required="false" default="all" />
    <cfargument name="delimiters" type="string" required="false" default="," />

    <cfset var returnValue = "" />
    <cfset var position = 0 />

    <cfif NOT ListFindNoCase("one,all", arguments.scope)>
        <cfthrow errorcode="ListRemove" message="Invalid argument SCOPE. Valid values are ONE and ALL." />
    </cfif>

    <cfloop list="#arguments.string1#" index="value" delimiters="#arguments.delimiters#">
        <cfset position = ListFindNoCase(arguments.string2, value, arguments.delimiters) />
        
        <cfif position gt 0 AND arguments.scope eq "one">
            <cfset arguments.string2 = ListDeleteAt(arguments.string2, position) />
        <cfelseif position eq 0>
            <cfset returnValue = ListAppend(returnValue, value, arguments.delimiters) />
        </cfif>
    </cfloop>

    <cfreturn returnValue />
</cffunction>

Click more for a view of example results against some test data.

Data

listOne 1,2,2,3,4,a,b,C,D
listTwo 0,1,2,T,D,B

ListRemove()

ListRemove(listOne, listTwo) 3,4,a,b,C
ListRemove(listTwo, listOne) 0,T,B
ListRemove(listOne, listTwo, "one") 2,3,4,a,b,C
ListRemove(listTwo, listOne, "one") 0,T,B

ListRemoveNoCase()

ListRemoveNoCase(listOne, listTwo) 3,4,a,C
ListRemoveNoCase(listTwo, listOne) 0,T
ListRemoveNoCase(listOne, listTwo, "one") 2,3,4,a,C
ListRemoveNoCase(listTwo, listOne, "one") 0,T

 
Comments are not allowed for this entry.
Jon Hartmann, July 2011

I'm Jon Hartmann and I'm a Javascript fanatic, UX/UI evangelist and former ColdFusion master. I blog about mysterious error messages, user interface design questions, and all things baffling and irksome about programming for the web.

Learn more about me on LinkedIn.