Reputation: 35339
I have a function that receives a string of tags. In order to save the tags individually, the function transforms the string into an array:
this.tags = listToArray(this.tags, ", ");
How do I remove duplicate values in the event that there are any?
Upvotes: 12
Views: 17174
Reputation: 219
I like to use Java for this kind of task:
<cfset tags = "apples,oranges,bananas,pears,apples" />
<cfset tagsArray = createObject("java", "java.util.ArrayList").init(
createObject("java", "java.util.HashSet").init(ListToArray(tags))
) />
<cfdump var="#tags#" />
<cfdump var="#tagsArray#" />
Only problem is it takes case into account, so thinks "apples" & "APPLES" are different things (which technically yes, depending on your system may well be different). Way round that is to lower case everything in the list first. (NOTE: Added java.util.ArrayList
function so that the array is identified & reusable by Adobe ColdFusion; otherwise functions like arraysort
will throw an error.)
Upvotes: 21
Reputation: 375
I'm posting another neat solution I like.
arrayReduce(arrayWithDuplicates, function(resultArr, item) {
if(!arrayFind(resultArr, item)){
arrayAppend(resultArr, item);
}
return resultArr;
}, [])
ArrayReduce
is available from ColdFusion 11.
But to answer better for the question, from the ColdFusion 10, we have ListRemoveDuplicates
function available.
So the final code may looks like this:
this.tags = listToArray(listRemoveDuplicates(this.tags, ", "), ", ");
Upvotes: 0
Reputation: 123
Since you're really starting with a string/list that you're then converting to an array, you can pass the string through ListRemoveDuplicates before converting the to an array. ListRemoveDuplicates was introduced in Coldfusion 10; the input parameters are (list, delimiter=",", ignoreCase=FALSE).
this.tags = listToArray(listRemoveDuplicates(arrayInput,", ",TRUE));
If you were actually starting with an array, you would need to convert it to a list first, then back again after.
this.tags = listToArray(listRemoveDuplicates(arrayToList(arrayInput),", ",TRUE) );
Upvotes: 10
Reputation: 13886
Taking jason's answer just a little bit further, here is an arrayDistinct
function.
function arrayDistinct (required array data) {
var output = arrayNew(1);
output.addAll(createObject("java", "java.util.HashSet").init(arguments.data));
return output;
}
You can test it here: https://trycf.com/gist/62ff904d4500519e3144fc9564d2bce7/acf
Upvotes: 1
Reputation: 1951
In Coldfusion 10 or Railo 4, you could use Underscore.cfc's uniq() function:
_ = new Underscore();
uniqueArray = _.uniq(arrayWithDuplicates);
One advantage of uniq()
is that it allows you to pass a transformation function, if necessary.
Note: I wrote Underscore.cfc
Upvotes: 2
Reputation: 842
Just put the array into a Struct and then copy it back to an array ;)
http://www.bennadel.com/blog/432-Using-ColdFusion-Structures-To-Remove-Duplicate-List-Values.htm
Upvotes: 0
Reputation: 11054
I just had to de-dup a very large list (5k+entries) and found a much faster way than using a loop. I feel the need to share.
<cfset thisArray = ListToArray(thisList)>
<cfset thisQuery = QueryNew("")>
<cfset temp = QueryAddColumn(thisQuery,"items","varChar",thisArray)>
<cfquery name="qItems" dbtype="query">SELECT DISTINCT items FROM thisQuery</cfquery>
<cfset returnString = ValueList(qItems.items)>
I wrote this into a function for easy use:
<cffunction name="deDupList" output="no" returntype="string">
<cfargument name="thisList" required="yes">
<cfargument name="thisDelimeter" required="yes" default=",">
<cfset var loc = StructNew()>
<cfset loc.thisArray = ListToArray(thisList,thisDelimeter)>
<cfset loc.thisQuery = QueryNew("")>
<cfset loc.temp = QueryAddColumn(loc.thisQuery,"items","varChar",loc.thisArray)>
<cfquery name="qItems" dbtype="query">
SELECT DISTINCT items FROM loc.thisQuery
</cfquery>
<cfset loc.returnString = ValueList(qItems.items)>
<cfreturn loc.returnString>
</cffunction>
I bench-marked it against a few other methods and here are the results in milliseconds:
Looping over List checking for > 1 instance: 6265
Using Henry's struct method: 2969
The above method: 31
Jason's Method: 30
Upvotes: 1
Reputation: 32885
based on idea of Jason Haritou, but you can do it in pure CF using Struct! (keys matching will be case-insensitive)
this.tags = listToArray(this.tags, ", ");
var tmpStruct = {};
for (var t in this.tags)
tmpStruct[t] = "";
return structKeyArray(tmpStruct);
However, for small lists, I prefer Antony's solution.
Upvotes: 2
Reputation: 403
There are a couple of UDF's on CFLib that do this, ArrayyDiff (http://www.cflib.org/udf/arrayDiff) and ArrayCompare (http://www.cflib.org/udf/arrayCompare).
hth, larry
Upvotes: -1
Reputation: 3781
An easy way to remove duplicates from a list is to convert the list to a struct first, and then conver the struct to an array. However if the order of items in the list is important this may not be appropriate as the elements in the struct will be sorted.
If the order of items is important you would need to build the array manually rather than using the listToArray feature.
<!--- CF9 --->
<cfset tags = "apples,oranges,bananas,pears,APPLES" />
<cfset tagArray = arrayNew(1) />
<cfloop list="#tags#" index="tag" delimiters=",">
<cfif not ArrayFindNoCase(tagArray,tag)>
<cfset arrayAppend(tagArray, tag) />
</cfif>
</cfloop>
Upvotes: 12