如何从Array Coldfusion中删除重复值

问题描述 投票:0回答:2

如何从Coldfusion中的数组列表中删除重复值。

目前我有以下内容显示用户去医院的原因:

<cfset ReasonforVisit = "#HospitalVisits2.Reason_For_Visit#">
    <cfset counter1 = 1>
    <cfif len(ReasonforVisit)>
      <cfloop query="HospitalVisits2">  
        <cfoutput>
            &nbsp;#HospitalVisits2.Reason_For_Visit#<cfif counter1 LT HospitalVisits2.recordcount>,</cfif>  <cfset counter1++>
        </cfoutput>
      </cfloop></cfif>

这种方法的问题在于没有考虑列中的dupes。

我已经完成以下操作以将列的结果存储在一个数组中,并检查是否但是无效。我究竟做错了什么?

<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>
coldfusion
2个回答
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>

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)中获取值并将该数组-theh事物转换为该列(https://cfdocs.org/valuelist)的分隔值列表。它可以采用可选的delimiter参数,允许我们更改列表的分隔符。我选择将,的默认值更改为|字符,这样如果我们的任何项目都有逗号,则以后不会在列表中意外地解释它。

现在我们已经有一个|分隔的Reason_For_Visit列表,我们可以使用该列表上的List函数来摆脱欺骗。这个功能非常巧妙地命名为listRemoveDuplicates()https://cfdocs.org/listremoveduplicates)。它可以采用两个可选参数:列表的已定义分隔符,以及是否忽略列表中字符串大小写的布尔值。我们给它在valueList()中设置的分隔符并告诉它忽略重复的情况,并且我们有一个去掉的列表。

现在我们只需要更改字符串中的分隔符,使它们不是|。幸运的是,Coldfusion有另一个巧妙命名的List Function,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

© www.soinside.com 2019 - 2024. All rights reserved.