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?
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?
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>
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.)
if (ArrayLen(createObject("java", "java.util.HashSet").init(cfQuery[colName]).toArray()) GT 1)
–
Morgue java.util.ArrayList
based on example here barneyb.com/barneyblog/2008/05/08/use-coldfusion-use-java otherwise the "array" couldn't be reused as an CFML array. –
Tana 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>
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) );
ListRemoveDuplicates
got added with ColdFusion 10. Don't try it on earlier versions. –
Lingcod 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.
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
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
HashSet
. It is lightening fast for me with over 10K items. I even cheated and passed the results back into a Vector to make CF happy. –
Holliman HashSet
. But interesting that a QoQ is faster than I would have expected. –
Holliman 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
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
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, ", "), ", ");
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
© 2022 - 2024 — McMap. All rights reserved.