代码之家  ›  专栏  ›  技术社区  ›  Kip

如何对coldfusion中的结构数组排序

  •  19
  • Kip  · 技术社区  · 15 年前

    我在coldfusion中有一组结构。我想根据结构中的一个属性对这个数组进行排序。我怎样才能做到这一点?我找到了structSort函数,但它需要一个结构和一个数组。

    如果这完全不可能在CaldF聚聚变中,那么在Java中有可能吗? Arrays.sort(Object[], Comparator) ?

    9 回复  |  直到 7 年前
        1
  •  12
  •   Tomalak    12 年前

    像往常一样,cflib.org有你想要的东西。

    http://cflib.org/udf/ArrayOfStructsSort

    /**
    * Sorts an array of structures based on a key in the structures.
    *
    * @param aofS      Array of structures.
    * @param key      Key to sort by.
    * @param sortOrder      Order to sort by, asc or desc.
    * @param sortType      Text, textnocase, or numeric.
    * @param delim      Delimiter used for temporary data storage. Must not exist in data. Defaults to a period.
    * @return Returns a sorted array.
    * @author Nathan Dintenfass (nathan@changemedia.com)
    * @version 1, December 10, 2001
    */
    function arrayOfStructsSort(aOfS,key){
            //by default we'll use an ascending sort
            var sortOrder = "asc";        
            //by default, we'll use a textnocase sort
            var sortType = "textnocase";
            //by default, use ascii character 30 as the delim
            var delim = ".";
            //make an array to hold the sort stuff
            var sortArray = arraynew(1);
            //make an array to return
            var returnArray = arraynew(1);
            //grab the number of elements in the array (used in the loops)
            var count = arrayLen(aOfS);
            //make a variable to use in the loop
            var ii = 1;
            //if there is a 3rd argument, set the sortOrder
            if(arraylen(arguments) GT 2)
                sortOrder = arguments[3];
            //if there is a 4th argument, set the sortType
            if(arraylen(arguments) GT 3)
                sortType = arguments[4];
            //if there is a 5th argument, set the delim
            if(arraylen(arguments) GT 4)
                delim = arguments[5];
            //loop over the array of structs, building the sortArray
            for(ii = 1; ii lte count; ii = ii + 1)
                sortArray[ii] = aOfS[ii][key] & delim & ii;
            //now sort the array
            arraySort(sortArray,sortType,sortOrder);
            //now build the return array
            for(ii = 1; ii lte count; ii = ii + 1)
                returnArray[ii] = aOfS[listLast(sortArray[ii],delim)];
            //return the array
            return returnArray;
    }
    
        2
  •  12
  •   Tomalak    9 年前

    这里有些东西和原来的很像 StructSort() . 它还支持 pathToSubElement 争论。

    <cffunction name="ArrayOfStructSort" returntype="array" access="public" output="no">
      <cfargument name="base" type="array" required="yes" />
      <cfargument name="sortType" type="string" required="no" default="text" />
      <cfargument name="sortOrder" type="string" required="no" default="ASC" />
      <cfargument name="pathToSubElement" type="string" required="no" default="" />
    
      <cfset var tmpStruct = StructNew()>
      <cfset var returnVal = ArrayNew(1)>
      <cfset var i = 0>
      <cfset var keys = "">
    
      <cfloop from="1" to="#ArrayLen(base)#" index="i">
        <cfset tmpStruct[i] = base[i]>
      </cfloop>
    
      <cfset keys = StructSort(tmpStruct, sortType, sortOrder, pathToSubElement)>
    
      <cfloop from="1" to="#ArrayLen(keys)#" index="i">
        <cfset returnVal[i] = tmpStruct[keys[i]]>
      </cfloop>
    
      <cfreturn returnVal>
    </cffunction>
    

    使用/测试:

    <cfscript> 
      arr = ArrayNew(1);
    
      for (i = 1; i lte 5; i = i + 1) {
        s = StructNew();
        s.a.b = 6 - i;
        ArrayAppend(arr, s);
      }
    </cfscript> 
    
    <cfset sorted = ArrayOfStructSort(arr, "numeric", "asc", "a.b")>
    
    <table><tr>
      <td><cfdump var="#arr#"></td>
      <td><cfdump var="#sorted#"></td>
    </tr></table>
    

    结果:

    ArrayOfStructSort Result

        3
  •  5
  •   jpswain    14 年前

    接受的解决方案(来自cflib.org)不安全。我用它做了一些工作上需要做的事情,结果发现当用浮点数对数字排序时,它返回的结果不正确。

    例如,如果我有这些结构:(伪代码)

    
    a = ArrayNew(1);
    
    s = StructNew();
    s.name = 'orange';
    s.weight = 200;
    ArrayAppend(a, s);
    
    s = StructNew();
    s.name = 'strawberry';
    s.weight = 28;
    ArrayAppend(a, s);
    
    s = StructNew();
    s.name = 'banana';
    s.weight = 90.55;
    ArrayAppend(a, s);
    
    sorted_array = arrayOfStructsSort(a, 'weight', 'asc', 'numeric');
    
    

    遍历排序数组并打印名称和权重。 顺序不对,这是混合的限制 对值进行排序的任意键。

        4
  •  4
  •   Russ    11 年前

    你可以使用 Underscore.cfc library 要完成你想要的:

    arrayOfStructs = [
        {myAttribute: 10},
        {myAttribute: 30},
        {myAttribute: 20}
    ];
    
    _ = new Underscore();
    
    sortedArray = _.sortBy(arrayOfStructs, function (struct) {
        return struct.myAttribute;
    });
    

    underline.cfc允许您定义自定义比较器并委托给arraysort()。您可以使用它对数组、结构、查询或字符串列表进行排序,但它总是返回一个数组。

    (免责声明:我写了下划线.cfc)

        5
  •  2
  •   hairbo    12 年前

    我想把我的两分钱投进去。我遇到了一个需要使用多个键对结构数组进行排序的情况。最后我使用一个构造好的查询来进行排序。函数将结构数组作为第一个参数,然后是表示排序顺序的结构数组,如下所示:

    <cfset result = sortArrayOfStructsUsingQuery(myArrayOfStructs,[
    {name = "price", type = "decimal", sortOrder = "asc"},
    {name = "id", type = "integer", sortOrder = "asc"}
    ])>
    

    在sortarrayofstructusingquery函数中,我只基于传入的键构造一个查询,然后对该查询进行排序。然后,循环查询,从数组中找到与当前查询行中的数据匹配的结构元素,并将该结构添加到我返回的数组中。

    这段代码中完全有可能存在一个我的测试没有发现的漏洞(我还没有发现很多用例),但如果它对任何人都有用的话,就在这里。希望它有用,如果有任何明显的漏洞,我很高兴听到他们。

    (只需注意:我使用“local”作用域来处理函数中的所有变量,使用“r”作用域来处理任何我打算返回的值的变量)

    <cffunction name="sortArrayOfStructsUsingQuery" output="yes" returnType="array">
    <cfargument name="array" type="array" required="true">
    <cfargument name="sortKeys" type="array" required="true">
    
    <cfset var local = {
        order = {
            keyList = "",
            typeList = "",
            clause = ""
        },
        array = duplicate(arguments.array),
        newArray = []
    }>
    
    <cfset var r = {
        array = []
    }>
    
    <cftry>
    
        <!--- build necessary lists out of given sortKeys array --->
        <cfloop array=#arguments.sortKeys# index="local.key">
            <cfset local.order.keyList = listAppend(local.order.keyList, local.key.name)>
            <cfset local.order.typeList = listAppend(local.order.typeList, local.key.type)>
            <cfset local.order.clause = listAppend(local.order.clause, "#local.key.name# #local.key.sortOrder#")>
        </cfloop>
    
    
        <!--- build query of the relevant sortKeys --->
        <cfset local.query = queryNew(local.order.keyList, local.order.typeList)>   
        <cfloop array=#arguments.array# index="local.obj">
            <cfset queryAddRow(local.query)>
            <cfloop list=#local.order.keyList# index="local.key">
                <cfset querySetCell(local.query, local.key, structFind(local.obj, local.key))>
            </cfloop>
        </cfloop>
    
        <!--- sort the query according to keys --->
        <cfquery name="local.sortedQuery" dbtype="query">
            SELECT *
              FROM [local].query
             ORDER BY #local.order.clause#
        </cfquery>
    
        <!--- rebuild the array based on the sorted query, then hand the sorted array back --->
        <cfloop query="local.sortedQuery">
            <cfloop from=1 to=#arraylen(local.array)# index=local.i>
    
                <cfset local.matchP = true>
                <cfloop list=#local.order.keylist# index="local.key">
                    <cfif structKeyExists(local.array[local.i], local.key)
                      AND structFind(local.array[local.i], local.key) EQ evaluate("local.sortedQuery.#local.key#")>
                          <cfset local.matchP = true>
                    <cfelse>
                        <cfset local.matchP = false>
                        <cfbreak>
                    </cfif>
                </cfloop>      
    
                <cfif local.matchP>
                    <cfset arrayAppend(r.array, local.array[local.i])>
                <cfelse>
                    <cfif NOT arrayContains(local.newArray, local.array[local.i])>
                        <cfset arrayAppend(local.newArray, local.array[local.i])>
                    </cfif>
                </cfif>
    
            </cfloop>
    
            <cfset local.array = local.newArray>
    
        </cfloop>
    
        <!--- Outbound array should contain the same number of elements as inbound array --->
        <cfif arrayLen(r.array) NEQ arrayLen(arguments.array)>
            <!--- log an error here --->
            <cfset r.array = arguments.array>
        </cfif>
    
    <cfcatch type="any">
                <!--- log an error here --->
        <cfset r.array = arguments.array>
    </cfcatch>
    
    </cftry>
    
    <cfreturn r.array>
    
    </cffunction>
    
        6
  •  2
  •   mikest34    11 年前

    使用新的cf闭包支持实际上更容易。

    下面是我今天工作的一个例子,我想按照存储在结构中的日期对结构数组进行排序。我是按降序排序的。

    ArraySort(yourArrayOfStructs, function(a,b) {
        if ( DateCompare(a.struct_date, b.struct_date) == -1 ) {
            return true;
        } else {
            return false;
        }
    });
    

    我不能完全相信,因为我改编自雷·卡姆登的《2012年关闭》。

        7
  •  2
  •   thdoan    9 年前

    这里有一个基于tomalak答案的udf,它也支持自定义对象(例如,一些基于railo的cms使用)。此函数与ColdFusion 9兼容。

    <cffunction name="sortStructArray" returntype="array" access="public">
      <cfargument name="base" type="array" required="yes">
      <cfargument name="sortType" type="string" required="no" default="text">
      <cfargument name="sortOrder" type="string" required="no" default="ASC">
      <cfargument name="pathToSubElement" type="string" required="no" default="">
      <cfset var _sct = StructNew()>
      <cfset var _aryKeys = ArrayNew(1)>
      <cfset var arySorted = ArrayNew(1)>
      <cfif IsStruct(base[1])>
        <!--- Standard structure --->
        <cfloop from="1" to="#ArrayLen(base)#" index="i">
          <cfset _sct[i] = base[i]>
        </cfloop>
        <cfset _aryKeys = StructSort(_sct, sortType, sortOrder, pathToSubElement)>
        <cfloop from="1" to="#ArrayLen(_aryKeys)#" index="i">
          <cfset arySorted[i] = _sct[_aryKeys[i]]>
        </cfloop>
      <cfelse>
        <!--- Custom object (e.g., Catalog) --->
        <cfloop from="1" to="#ArrayLen(base)#" index="i">
          <cfset _sct[i] = StructNew()>
          <cfset _sct[i][pathToSubElement] = base[i][pathToSubElement]>
        </cfloop>
        <cfset _aryKeys = StructSort(_sct, sortType, sortOrder, pathToSubElement)>
        <cfloop from="1" to="#ArrayLen(_aryKeys)#" index="i">
          <cfset arySorted[i] = base[_aryKeys[i]]>
        </cfloop>
      </cfif>
      <cfreturn arySorted>
    </cffunction>
    
        8
  •  2
  •   DaveB    7 年前

    我对上面的@mikest34帖子没有什么好的评价,但是@russ说的对,这个回调不再像之前解释的那样工作了。

    亚当·卡梅隆发现,当使用带有回调的arraysort时,它不再需要true/false响应,而是:

    -1,如果第一个参数比第二个参数小
    0,如果第一个参数等于第二个参数
    1,第一个参数比第二个参数大

    所以正确的回调是:

    ArraySort(yourArrayOfStructs, function(a,b) {
        return compare(a.struct_date, b.struct_date);
    });
    

    在CF2016进行测试和工作

        9
  •  1
  •   zarko.susnjar    15 年前

    如果不想使用自定义方法,coldfusion有 结构排序 方法 http://www.cfquickdocs.com/cf8/#StructSort . 是的,它使用嵌套结构对结构进行排序,但返回数组,因此可以用来获得相同的结果。