This came in via my forums today and I thought it was too interesting to not blog about. If you read his post, you can see he needs to support rotating data such that A B C changes to B A C. However, he also has groupings within his data. So imagine now you have ABC in the first group and DE in the second. Your rotation now needs to be "in" group, so on your first iteration you have: A B C D E. On your second you rotate each group to end with: B C A E D. I whipped up the following solution and I'd love to see alternatives.

I began by creating a data structure. SuperAlly mentioned a query but for now I assume the query data is converted into a 2D array.

<cfset data = [ ["a", "b", "c"], ["d", "e"] ]>

Next I whipped up a quick UDF that would display this data. It assumes you pass in a 2D array and simply loops through each element:

<cfscript> function render(arr) { for(var i=1; i<=arrayLen(arr); i++) { for(var x=1; x<=arrayLen(arr[i]); x++) { writeOutput(arr[i][x] & " "); } } } </cfscript>

I displayed this to ensure everything was kosher:

<cfoutput> #render(data)# <p/> </cfoutput>

This returned "a b c d e" as I expected. Ok, now for the fun part. In theory, all I have to do is remove the item from the beginning of each array and drop it on top.

<cfloop index="i" from="1" to="#arrayLen(data)#"> <cfset movingItem = data[i][1]> <cfset arrayDeleteAt(data[i],1)> <cfset arrayAppend(data[i], movingItem)> </cfloop>

As you can see, I loop over data, which is the core data holder. Each element of data is an array itself. I grab the first item, delete it, and then simply add it to the end of the array. Here is a complete script with a few sample runs:

<cfset data = [ ["a", "b", "c"], ["d", "e"] ]>

<cfscript> function render(arr) { for(var i=1; i<=arrayLen(arr); i++) { for(var x=1; x<=arrayLen(arr[i]); x++) { writeOutput(arr[i][x] & " "); } } } </cfscript>

<cfoutput> #render(data)# <p/> </cfoutput>

<cfloop index="i" from="1" to="#arrayLen(data)#"> <cfset movingItem = data[i][1]> <cfset arrayDeleteAt(data[i],1)> <cfset arrayAppend(data[i], movingItem)> </cfloop>

<cfoutput> #render(data)# <p/> </cfoutput>

<cfloop index="i" from="1" to="#arrayLen(data)#"> <cfset movingItem = data[i][1]> <cfset arrayDeleteAt(data[i],1)> <cfset arrayAppend(data[i], movingItem)> </cfloop>

<cfoutput> #render(data)# <p/> </cfoutput>

And the output:

a b c d e

b c a e d

c a b d e

Notice how the second group, D E, correctly works even though it is smaller than the first group, A B C.