如何在Coldfusion中从数组列表中删除重复的值。
当前,我有以下内容显示用户去医院的原因:
<cfset ReasonforVisit = "#HospitalVisits2.Reason_For_Visit#">
<cfset counter1 = 1>
<cfif len(ReasonforVisit)>
<cfloop query="HospitalVisits2">
<cfoutput>
#HospitalVisits2.Reason_For_Visit#<cfif counter1 LT HospitalVisits2.recordcount>,</cfif> <cfset counter1++>
</cfoutput>
</cfloop></cfif>
这种方法的问题没有考虑到列中的重复。
我已经完成了以下操作,以将列的结果存储在数组中,并检查是否重复,但是不起作用。我在做什么错了?
<cfset ReasonforVisit = "#HospitalVisits2.Reason_For_Visit#">
<cfset ReasonList = ArrayNew(ReasonforVisit)>
<cfloop index="i" from="1" to="#arraylen(ReasonList)#">
<cfset currReasonList = ReasonList[i]>
<cfset nextReasonList = ReasonList[i+1]>
<cfif currReasonList NEQ nextReasonList>
<cfset newReasonList = ArrayNew(newcurrReasonList)>
<cfelse>
</cfif>
</cfloop>
<cfoutput>#newReasonList#</cfoutput>
答案 0 :(得分:2)
这是一个Lucee功能请求。也许您可以使用此页面上的示例:
https://luceeserver.atlassian.net/browse/LDEV-442
<cfscript>
s = "a string";
i = 42;
f = pi();
st1 = {key1="value1"};
st1bis = {key1="value1"};
st1ref = st1;
st2 = {key2="value2"};
a1 = [1];
a1bis = [1];
a1ref = a1;
a2 = [2];
base = [s,i,f,st1,st1bis,st1ref,st2,a1,a1bis,a1ref,a2,s,i,f,st1,st1bis,st1ref,st2,a1,a1bis,a1ref,a2];
function arrayRemoveDuplicates(array){
return array.reduce(function(deduped, el){
return deduped.find(el) ? deduped : deduped.append(el);
}, []);
}
writeDump(var=base, label="original")
writeDump(var=arrayRemoveDuplicates(base), label="deduped")
</cfscript>
答案 1 :(得分:2)
我可能会误解您真正想要的东西,如果是,我将更改答案。根据显示的内容,您不想从数组中删除值。您要输出以逗号分隔的Reason_For_Visit
列表,其中删除了所有重复项,对吗?
ColdFusion查询对象非常易于使用,并且自从该语言诞生之初就一直是CF最强大的功能之一。
ColdFusion查询对象已经具有许多数组和结构的属性,并且可以将那些复杂数据类型的许多相同功能和行为应用于cfquery对象。
您要的内容基本上可以在一行中完成(包含一些功能)。
newReasonList = listChangeDelims(
listRemoveDuplicates(
valuelist(HospitalVisits2.Reason_For_Visit, "|")
,"|"
,true
)
,", "
,"|"
,false
) ;
我知道这显示为多行,但是我以这种方式格式化以使其更清晰,因为我讨厌在页面上滚动。 :-)
看看我们在做什么:
我们的查询对象是Reason_For_Visit
查询的HospitalVisits2
列。 valueList()
是用于处理查询的最古老的CF函数之一。它将本质上从查询列(HospitalVisits2.Reason_For_Visit
)中获取值,并将类似于数组的内容转换为该列(https://cfdocs.org/valuelist)的定界值列表。它可以使用可选的delimiter
参数,该参数允许我们更改列表的定界符。我选择将,
的默认值更改为|
字符,这样,如果我们的任何项目都有逗号,以后就不会在列表中无意间解释它。
现在我们有了一个|
分隔的Reason_For_Visit
列表,我们可以在该列表上使用列表函数来消除重复对象。该函数非常聪明地命名为listRemoveDuplicates()
(https://cfdocs.org/listremoveduplicates)。它可以包含两个可选参数:列表的已定义定界符,以及是否忽略列表中字符串大小写的布尔值。我们给它一个在valueList()
中设置的定界符,并告诉它忽略重复的情况,并且我们有一个重复数据删除列表。
现在,我们只需要更改字符串中的定界符即可,使它们不再|
。幸运的是,Coldfusion还有另一个巧妙命名的列表函数listChangeDelims()
(https://cfdocs.org/listchangedelims)。此函数接受我们的列表和所需的新定界符的参数。默认为逗号。它还需要两个可选参数。我们可以指定当前的分隔符(|
),然后告诉我们要包含空值。在这里,我们可能不希望这些容器为空。这样可以给我们一个像Thing1, Thing2,,Thing4
这样的列表。
valueList()
太旧了,可以在任何版本的ColdFusion甚至是半兼容的CFML解析器中使用。 listRemoveDuplicates()
和listChangeDelims()
已添加到CF10中,并且在Lucee 4.5+中可用。显然,TryCF指示它仍将在Railo 4.2中运行。如果您使用的是旧版本,则删除这些重复项会比较棘手,并且可能会更慢。
我在https://trycf.com/gist/8e3107959cc051dd264b850bbeae88e3/acf?theme=monokai创建了一个示例。您还可以看到,这些函数将处理一个空查询,一个元素查询和一个空元素查询。您不会收到流浪逗号。
还有其他方法可以做到这一点,但我不确定它如何在非常大的列表中扩展,但这很快就会起作用。如果您需要遍历多个患者以输出其原因,则可以很容易地修改此方法。对于较新版本的CF,可以使用闭包和其他东西来使其更快一些。
================================================ =
编辑:针对CFMX进行了修改
https://trycf.com/gist/91bc66f0fd0b7597e7a4652e9d255e41/acf?theme=monokai
我应该注意,我目前尚无法测试像CFMX一样古老的产品,因此我的内存不足。我不记得是否可以在CFMX的valueList()
和structKeyList()
中设置定界符。可以将其删除,您仍然会得到一个逗号分隔的列表。逗号后只是没有多余的空间。您必须进行测试。
从本质上讲,您可以循环查询并构建一个结构(本质上不会插入重复的键),,但是当我尝试输出结构键列表时却看到一个逗号开头,这需要附加正在处理以删除该逗号。因此,我认为更简洁的方法可能能够遍历值列表,而不是遍历查询。我知道循环遍历列表要比循环遍历查询慢,但是我不确定这对您的规模有多大影响。我去了:
<!--- create the struct --->
<cfset newReasonStruct = StructNew() />
<!--- CF Structs will overwrite duplicate keys. --->
<!--- NOTE: I can't remember if delimiters were valid arguments for valuelist() in CFMX --->
<cfloop index="VisitReason" list="#valuelist(HospitalVisits2.Reason_For_Visit, "|")#" delimiters="|">
<cfif len(trim(Reason_For_Visit))> <!--- Don't add empties. --->
<cfset newReasonStruct[VisitReason] = "" >
</cfif>
</cfloop>
<!--- Set a variable for our new list. --->
<cfset newReasonList = StructKeyList(newReasonStruct,", ") >
This is our main query (with valuelist()): <cfoutput>#newReasonList#</cfoutput>
编辑2:参见上面的我的删除线。我没想前导逗号是由查询循环中的空元素引起的。这导致“键”值为空字符串,然后将其排序到我的输出字符串的开头。 valueList()
列表循环方法正在过滤掉该空元素,但查询循环却没有。因此,可以通过更改查询循环并在结构为空的情况下不向结构中添加“键”来完成修剪前导逗号的额外处理。但是,这从最后的一组cfif/right()
函数变为查询中每个循环的len(trim())
函数。同样,根据您的数据,一个功能可能比另一个功能更高效。尽管这有点像微优化。
<!--- CF Structs will overwrite duplicate keys. --->
<cfloop query="HospitalVisits2">
<cfif len(trim(Reason_For_Visit))> <!--- Don't add empties. --->
<cfset newReasonStruct[Reason_For_Visit] = "" >
</cfif>
</cfloop>
https://trycf.com/gist/169e9e0a592bf88aac462cc3a6e0d2c6/acf?theme=monokai
答案 2 :(得分:0)
更快,更现代:
public array function arrayUnique(required array sourceArray){
var source = arguments.sourceArray;
return source.filter((item, index) => source.find(arguments.item) == arguments.index);
}