Я хотел бросить свои два цента здесь. Я столкнулся с ситуацией, когда мне нужно было отсортировать массив структур, используя более одного ключа. Я закончил с помощью построенного запроса, чтобы выполнить сортировку. Функция принимает массив структур в качестве первого аргумента, а затем массив структур, указывающих порядок сортировки, например:
<cfset result = sortArrayOfStructsUsingQuery(myArrayOfStructs,[
{name = "price", type = "decimal", sortOrder = "asc"},
{name = "id", type = "integer", sortOrder = "asc"}
])>
В функции sortArrayOfStructsUsingQuery, я построить запрос, основанный только на клавишах я передать в , затем отсортируйте этот запрос. Затем, перейдя по запросу, найдите элемент структуры из массива, который соответствует данным в текущей строке запроса, и добавьте эту структуру в массив, который я передаю.
Вполне возможно, что в этом коде есть зияющее отверстие, которое не было обнаружено моим тестированием (пока у меня не было много вариантов использования), но в случае, если это полезно кому-либо, вот оно. Надеюсь, это полезно, и если есть какие-то яркие дыры, я рад услышать о них.
(просто примечание: Я использую «локальную» область видимости для всех переменных, которые останутся в функции, и «г» сфера для чего я намерен передать обратно, за то, что стоит)
<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>
"ключи" должен быть вар-Scoped, я считаю. –
@Edward: Абсолютно, я пропустил это. Спасибо за подсказку. – Tomalak
Многие другие ответы здесь зависят от функции обратного вызова arraySort() (добавлена в функции CF10) или функции sort() (добавлено в CF11). Ответ Томалака работает, по крайней мере, на CF9, который я все еще должен поддерживать. Спасибо, Томалак! –