【问题标题】:How do I remove duplicate values from a Coldfusion array?如何从 Coldfusion 数组中删除重复值?
【发布时间】:2011-09-02 06:09:03
【问题描述】:

我有一个接收一串标签的函数。为了单独保存标签,该函数将字符串转换为数组:

this.tags = listToArray(this.tags, ", ");

如果存在重复值,如何删除?

【问题讨论】:

  • Java 中可用的“set”抽象数据类型专门用于解决此类问题。

标签: arrays coldfusion duplicates


【解决方案1】:

从列表中删除重复项的一种简单方法是先将列表转换为结构,然后再将结构转换为数组。但是,如果列表中项目的顺序很重要,这可能不合适,因为结构中的元素将被排序。

如果项目的顺序很重要,您需要手动构建数组,而不是使用 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>

【讨论】:

    【解决方案2】:

    我喜欢使用 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”是不同的东西(从技术上讲是的,取决于您的系统可能会有所不同)。方法是先将列表中的所有内容小写。

    【讨论】:

    • 谢谢。您是否做过任何测试/知道这是否比将值循环到 ColdFusion 结构中更快?
    • @Mohamad - 从纯粹的速度角度来看,我的猜测是 HashSet 更快。但是.. 除非您处理大量列表,否则差异通常很小。我通常会选择合适的方法,并且只有在它成为问题时才担心速度。
    • 这个解决方案的美妙之处在于它只需要一条线!在我的情况下,我需要找出冷融合查询中的特定字段是否具有多个唯一值。虽然这里列出的其他解决方案也可以,但这一行让我的代码非常简单:if (ArrayLen(createObject("java", "java.util.HashSet").init(cfQuery[colName]).toArray()) GT 1)
    • 杰森,感谢您的代码。从另一个系统中提取数据后,我有一组具有重复值的结构。我能够通过 HashSet 传递数组并最终得到一个重复数据删除的数组集。
    【解决方案3】:

    基于 Jason Haritou 的想法,但您可以使用 Struct 在纯 CF 中完成! (键匹配不区分大小写)

    this.tags = listToArray(this.tags, ", ");
    var tmpStruct = {};
    
    for (var t in this.tags)
        tmpStruct[t] = "";
    
    return structKeyArray(tmpStruct);
    

    但是,对于小型列表,我更喜欢 Antony 的解决方案。

    【讨论】:

    • 只是好奇,为什么要打扰 if 语句?结构不允许任何重复值,所以在这里使用条件是不是有点多余?
    【解决方案4】:

    CFLib 上有几个 UDF 可以做到这一点,ArrayyDiff (http://www.cflib.org/udf/arrayDiff) 和 ArrayCompare (http://www.cflib.org/udf/arrayCompare)。

    hth, 拉里

    【讨论】:

      【解决方案5】:

      我只需要删除一个非常大的列表(5k + 条目)并找到比使用循环更快的方法。我觉得有必要分享。

      1. 将列表转换为数组(你已经有了数组,所以跳过)&lt;cfset thisArray = ListToArray(thisList)&gt;
      2. 使用 queryNew("") &lt;cfset thisQuery = QueryNew("")&gt; 创建查询
      3. 使用 step1 中的数组将列添加到该查询&lt;cfset temp = QueryAddColumn(thisQuery,"items","varChar",thisArray)&gt;
      4. 查询不同的值&lt;cfquery name="qItems" dbtype="query"&gt;SELECT DISTINCT items FROM thisQuery&lt;/cfquery&gt;
      5. 将结果转换为列表&lt;cfset returnString = ValueList(qItems.items)&gt;
      6. 您可以轻松地将此列表转换回数组

      为了方便使用,我把它写成了一个函数:

      <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

      【讨论】:

      • (编辑)我可以看到循环有多慢。但我很惊讶你说 Jason 的方法很慢,即使用HashSet。超过 10,000 件物品对我来说速度很快。我什至作弊并将结果传回向量中以使 CF 高兴。
      • 我在实现 Jason 的方法时搞砸了我的基准测试脚本,愚蠢的错误。你是对的,他的速度非常快,纠正了我的基准测试结果。谢谢。
      • 谢谢。我可能会选择HashSet。但有趣的是,QoQ 比我预期的要快。
      【解决方案6】:

      只需将数组放入 Struct 中,然后将其复制回数组;)

      http://www.bennadel.com/blog/432-Using-ColdFusion-Structures-To-Remove-Duplicate-List-Values.htm

      【讨论】:

        【解决方案7】:

        在 Coldfusion 10 或 Railo 4 中,您可以使用 Underscore.cfc's uniq() function

        _ = new Underscore();
        
        uniqueArray = _.uniq(arrayWithDuplicates);
        

        uniq() 的一个优点是它允许您在必要时传递转换函数。

        注意:我写的是 Underscore.cfc

        【讨论】:

          【解决方案8】:

          由于您实际上是从一个字符串/列表开始,然后将其转换为数组,因此您可以在将字符串转换为数组之前通过ListRemoveDuplicates 传递字符串。 ListRemoveDuplicates 是在 Coldfusion 10 中引入的;输入参数是 (list, delimiter=",", ignoreCase=FALSE)。

          this.tags = listToArray(listRemoveDuplicates(arrayInput,", ",TRUE));
          

          如果您实际上是从数组开始,则需要先将其转换为列表,然后再返回。

          this.tags = listToArray(listRemoveDuplicates(arrayToList(arrayInput),", ",TRUE) );
          

          【讨论】:

          • 代码转储不是答案。请编辑您的答案并解释此代码是什么、它是如何工作的以及它如何回答问题。
          • 我想说代码不言自明。只需阅读它,就会清楚发生了什么。
          • 提示:ListRemoveDuplicates 是在 ColdFusion 10 中添加的。不要在早期版本上尝试。
          【解决方案9】:

          进一步了解 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

          【讨论】:

            【解决方案10】:

            我正在发布另一个我喜欢的简洁解决方案。

            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, ", "), ", ");
            

            【讨论】:

              猜你喜欢
              • 2015-09-24
              • 2011-08-05
              • 2018-02-13
              • 2014-10-10
              • 2019-10-19
              • 2018-01-18
              • 1970-01-01
              • 2021-07-29
              相关资源
              最近更新 更多