【发布时间】:2011-09-02 06:09:03
【问题描述】:
我有一个接收一串标签的函数。为了单独保存标签,该函数将字符串转换为数组:
this.tags = listToArray(this.tags, ", ");
如果存在重复值,如何删除?
【问题讨论】:
-
Java 中可用的“set”抽象数据类型专门用于解决此类问题。
标签: arrays coldfusion duplicates
我有一个接收一串标签的函数。为了单独保存标签,该函数将字符串转换为数组:
this.tags = listToArray(this.tags, ", ");
如果存在重复值,如何删除?
【问题讨论】:
标签: arrays coldfusion duplicates
从列表中删除重复项的一种简单方法是先将列表转换为结构,然后再将结构转换为数组。但是,如果列表中项目的顺序很重要,这可能不合适,因为结构中的元素将被排序。
如果项目的顺序很重要,您需要手动构建数组,而不是使用 listToArray 功能。
<!--- 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>
【讨论】:
我喜欢使用 Java 来完成这种任务:
<cfset tags = "apples,oranges,bananas,pears,apples" />
<cfset tagsArray = createObject("java", "java.util.HashSet").init(ListToArray(tags)).toArray() />
<cfdump var="#tags#" />
<cfdump var="#tagsArray#" />
唯一的问题是它会考虑大小写,因此认为“apples”和“APPLES”是不同的东西(从技术上讲是的,取决于您的系统可能会有所不同)。方法是先将列表中的所有内容小写。
【讨论】:
if (ArrayLen(createObject("java", "java.util.HashSet").init(cfQuery[colName]).toArray()) GT 1)
基于 Jason Haritou 的想法,但您可以使用 Struct 在纯 CF 中完成! (键匹配不区分大小写)
this.tags = listToArray(this.tags, ", ");
var tmpStruct = {};
for (var t in this.tags)
tmpStruct[t] = "";
return structKeyArray(tmpStruct);
但是,对于小型列表,我更喜欢 Antony 的解决方案。
【讨论】:
CFLib 上有几个 UDF 可以做到这一点,ArrayyDiff (http://www.cflib.org/udf/arrayDiff) 和 ArrayCompare (http://www.cflib.org/udf/arrayCompare)。
hth, 拉里
【讨论】:
我只需要删除一个非常大的列表(5k + 条目)并找到比使用循环更快的方法。我觉得有必要分享。
<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)>
为了方便使用,我把它写成了一个函数:
<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>
我用其他几种方法对其进行了基准测试,结果以毫秒为单位:
循环列表检查 > 1 个实例:6265
使用亨利的 struct 方法:2969
上述方法:31
杰森法:30
【讨论】:
HashSet。超过 10,000 件物品对我来说速度很快。我什至作弊并将结果传回向量中以使 CF 高兴。
HashSet。但有趣的是,QoQ 比我预期的要快。
只需将数组放入 Struct 中,然后将其复制回数组;)
http://www.bennadel.com/blog/432-Using-ColdFusion-Structures-To-Remove-Duplicate-List-Values.htm
【讨论】:
在 Coldfusion 10 或 Railo 4 中,您可以使用 Underscore.cfc's uniq() function:
_ = new Underscore();
uniqueArray = _.uniq(arrayWithDuplicates);
uniq() 的一个优点是它允许您在必要时传递转换函数。
注意:我写的是 Underscore.cfc
【讨论】:
由于您实际上是从一个字符串/列表开始,然后将其转换为数组,因此您可以在将字符串转换为数组之前通过ListRemoveDuplicates 传递字符串。 ListRemoveDuplicates 是在 Coldfusion 10 中引入的;输入参数是 (list, delimiter=",", ignoreCase=FALSE)。
this.tags = listToArray(listRemoveDuplicates(arrayInput,", ",TRUE));
如果您实际上是从数组开始,则需要先将其转换为列表,然后再返回。
this.tags = listToArray(listRemoveDuplicates(arrayToList(arrayInput),", ",TRUE) );
【讨论】:
ListRemoveDuplicates 是在 ColdFusion 10 中添加的。不要在早期版本上尝试。
进一步了解 jason 的回答,这里有一个 arrayDistinct 函数。
function arrayDistinct (required array data) {
var output = arrayNew(1);
output.addAll(createObject("java", "java.util.HashSet").init(arguments.data));
return output;
}
你可以在这里测试它:https://trycf.com/gist/62ff904d4500519e3144fc9564d2bce7/acf
【讨论】:
我正在发布另一个我喜欢的简洁解决方案。
arrayReduce(arrayWithDuplicates, function(resultArr, item) {
if(!arrayFind(resultArr, item)){
arrayAppend(resultArr, item);
}
return resultArr;
}, [])
ArrayReduce 可从 ColdFusion 11 获得。
但为了更好地回答这个问题,from the ColdFusion 10, we have ListRemoveDuplicates function available。
所以最终的代码可能是这样的:
this.tags = listToArray(listRemoveDuplicates(this.tags, ", "), ", ");
【讨论】: