volevo buttare i miei due centesimi in qui. Mi sono imbattuto in un caso in cui avevo bisogno di ordinare una matrice di strutture usando più di una chiave. Sono finito usando una query costruita per fare il mio smistamento. La funzione prende l'array di struct come primo argomento, e quindi un array di struct indicano l'ordinamento, in questo modo:
<cfset result = sortArrayOfStructsUsingQuery(myArrayOfStructs,[
{name = "price", type = "decimal", sortOrder = "asc"},
{name = "id", type = "integer", sortOrder = "asc"}
])>
All'interno della funzione sortArrayOfStructsUsingQuery, costruisco una query basata solo sulle chiavi mi passa , quindi ordina quella query. Quindi, eseguo il loop sulla query, trova l'elemento struttura dall'array che corrisponde ai dati nella riga di query corrente e aggiungo la struttura all'array che restituisco.
È completamente possibile che ci sia un buco aperto in questo codice che il mio test non ha scoperto (non ci sono stati ancora molti casi d'uso per me), ma nel caso sia utile a qualcuno, eccolo qui. Spero sia utile, e se ci sono buchi lampanti, sono felice di sentir parlare di loro.
(solo una nota: Io uso l'ambito "locale" per tutte le variabili che resteranno nella funzione, e la "r" portata per qualsiasi cosa ho intenzione di restituire, per quel che vale)
<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>
"chiavi" deve essere var con ambito, credo. –
@Edward: Assolutamente, ho perso quello. Grazie per il suggerimento. – Tomalak
Molte delle altre risposte dipendono dalla funzione di callback arraySort() (aggiunta in CF10) o sort() (aggiunta in CF11). La risposta di Tomalak funziona almeno su CF9, che devo ancora supportare. Grazie, Tomalak! –