Я хотел бросить свои два цента здесь.Я столкнулся с случаем, когда мне нужно было отсортировать массив структур, используя более одного ключа.Я использовал построенный запрос для сортировки.Функция принимает массив структур в качестве первого аргумента, а затем массив структур, указывающих порядок сортировки, например:
<cfset result = sortArrayOfStructsUsingQuery(myArrayOfStructs,[
{name = "price", type = "decimal", sortOrder = "asc"},
{name = "id", type = "integer", sortOrder = "asc"}
])>
В рамках функции sortArrayOfStructsUsingQuery я создаю запрос на основе только ключей, которые япередать, а затем отсортировать этот запрос.Затем я зацикливаю запрос, нахожу элемент структуры из массива, который соответствует данным в текущей строке запроса, и добавляю эту структуру в массив, который я возвращаю.
Вполне возможно, что в этом коде есть зияющая дыра, которую мое тестирование еще не раскрыло (пока для меня не было много вариантов использования), но в случае, если это кому-нибудь пригодится, вот оноявляется.Надеюсь, что это полезно, и если есть какие-то явные дыры, я рад услышать о них.
(только примечание: я использую "локальную" область видимости для всех переменных, которые останутся в функции, иобласть "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>