Posted in ColdFusion | Posted on 11-17-2009 | 2,351 views
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.
2 ["a", "b", "c"],
3 ["d", "e"]
4 ]>
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:
2function render(arr) {
3 for(var i=1; i<=arrayLen(arr); i++) {
4 for(var x=1; x<=arrayLen(arr[i]); x++) {
5 writeOutput(arr[i][x] & " ");
6 }
7 }
8}
9</cfscript>
I displayed this to ensure everything was kosher:
2#render(data)#
3<p/>
4</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.
2 <cfset movingItem = data[i][1]>
3 <cfset arrayDeleteAt(data[i],1)>
4 <cfset arrayAppend(data[i], movingItem)>
5</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:
2 ["a", "b", "c"],
3 ["d", "e"]
4 ]>
5
6
7<cfscript>
8function render(arr) {
9 for(var i=1; i<=arrayLen(arr); i++) {
10 for(var x=1; x<=arrayLen(arr[i]); x++) {
11 writeOutput(arr[i][x] & " ");
12 }
13 }
14}
15</cfscript>
16
17<cfoutput>
18#render(data)#
19<p/>
20</cfoutput>
21
22<cfloop index="i" from="1" to="#arrayLen(data)#">
23 <cfset movingItem = data[i][1]>
24 <cfset arrayDeleteAt(data[i],1)>
25 <cfset arrayAppend(data[i], movingItem)>
26</cfloop>
27
28<cfoutput>
29#render(data)#
30<p/>
31</cfoutput>
32
33<cfloop index="i" from="1" to="#arrayLen(data)#">
34 <cfset movingItem = data[i][1]>
35 <cfset arrayDeleteAt(data[i],1)>
36 <cfset arrayAppend(data[i], movingItem)>
37</cfloop>
38
39<cfoutput>
40#render(data)#
41<p/>
42</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.


I will let you know how I do as soon as I have a chance to sit down with it.
Thanks again.
Here they are in action,
The linked series: http://searisen.com/mg/?event=test.linkedSeries
The linked list: http://searisen.com/mg/?event=test.linkedList
If anyone has suggestions to licenses for releasing the CFC's, can you point me in the right direction?
Happy coding!
Unfortunately though, it seems (at least to me :) ) to be a lot more complicated than I had originally thought. There could, in theory, be far more than two groups of results within the query that would need to be sorted amongst themselves and then, being that it's a query of a db to begin with, every time someone viewed the results, it would start from the same place, therefore always removing the same first items from each 'group' to place at the end. (That is, even if I COULD get my query converted to an array properly without errors!! )
I think I may need to rethink my entire approach. If I look at the page and see a,b,c,d,e then you look at the page, you should see b,c,a,e,d, then I refresh the page, I should see c,a,b,d,e. So, I guess I need to keep track of which record was last viewed as the first record.
Anyway, sorry to ramble, apologies for the delayed response, and thanks again for the help!
[Add Comment] [Subscribe to Comments]