wollte ich hier meine zwei Cent werfen. Ich stieß auf einen Fall, in dem ich ein Array von Strukturen mit mehr als einem Schlüssel sortieren musste. Ich endete mit einer konstruierten Abfrage, um meine Sortierung durchzuführen. Die Funktion nimmt das Array von Strukturen als erstes Argument, und dann eine Reihe von structs die Reihenfolge angibt, wie folgt aus:
<cfset result = sortArrayOfStructsUsingQuery(myArrayOfStructs,[
{name = "price", type = "decimal", sortOrder = "asc"},
{name = "id", type = "integer", sortOrder = "asc"}
])>
Innerhalb der sortArrayOfStructsUsingQuery Funktion Konstrukt I einer Abfrage basiert nur auf den Tasten I passieren in , dann sortiere diese Abfrage. Dann wiederhole ich die Abfrage, finde das Strukturelement aus dem Array, das mit den Daten in der aktuellen Abfragezeile übereinstimmt, und füge diese Struktur dem Array hinzu, das ich zurückgebe.
Es ist durchaus möglich, dass es in diesem Code ein klaffendes Loch gibt, das meine Tests nicht aufgedeckt haben (es gab noch nicht viele Anwendungsfälle für mich), aber falls es für irgendjemanden nützlich ist, hier ist es. Ich hoffe, es ist nützlich, und wenn es irgendwelche grellen Löcher gibt, bin ich glücklich, von ihnen zu hören.
(nur eine Anmerkung: Ich benutze den „lokalen“ Spielraum für alle Variablen, die in der Funktion bleiben, und das „r“ Raum für alles, was ich beabsichtige, zurück zu geben, denn was es wert ist)
<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>
"Schlüssel" muss var-scoped sein, glaube ich. –
@Edward: Absolut, das habe ich vermisst. Danke für den Tipp. – Tomalak
Viele der anderen Antworten hängen hier von der arraySort() - Callback-Funktion (hinzugefügt in CF10) oder der sort() - Member-Funktion ab (hinzugefügt in CF11). Tomalaks Antwort funktioniert zumindest zurück zu CF9, die ich noch unterstützen muss. Danke, Tomalak! –