Randomly Sort A ColdFusion Array (Updated) - Thanks Mark Mandel

Posted September 20, 2006 at 1:48 PM by Ben Nadel

Tags: ColdFusion

I had recently posted a ColdFusion solution to randomly sorting an array. Mark Mandel graciously pointed out that in Java, there is already a way to do this utilizing the java.util.Collections class. The java.util.Collections class is comprised solely of static methods that manipulate collections. It just so happens that it has a method: Shuffle().

Implementing it in ColdFusion could not be easier:

  • <!--- Create an array. --->
  • <cfset arrGirls = ListToArray(
  • "Sarah,Ashley,Anna,Libby"
  • ) />
  •  
  • <!--- Shuffle it (ie. randomly sort it). --->
  • <cfset CreateObject(
  • "java",
  • "java.util.Collections"
  • ).Shuffle(
  • arrGirls
  • ) />

The code is compact so it may be hard to read. First, we are creating an instance of the Collections class:

  • <cfset CreateObject( "java", "java.util.Collections" ) />

This class has NO constructors, which is why we are not calling any Init() methods. Once we have the instance, we then call the static method Shuffle() and pass in the array, arrGirls. This method does not return a value. It is updating the array by reference, not value.

This should accept anything that implements the list interface, java.util.List.

How easy is that? Thanks a bunch Mark Mandel! Man, I really need to learn more about the Java 2 class libraries. There is so much stuff in there that is SOOO awesome for ColdFusion.




Reader Comments

Sep 29, 2006 at 8:19 AM // reply »
20 Comments

Wow, that's so much simpler than my method of getting a random selection of sidebar buttons from a SQL query (which basically entailed getting the first random number, getting the second and checking it wasn't the same as the first, getting the third etc...).

Not what you'd call efficient code, but I couldn't see an alternative!


Sep 29, 2006 at 9:38 AM // reply »
10,638 Comments

What can I say, Mark Mandel is the man :)


Jan 28, 2007 at 4:17 AM // reply »
1 Comments

THANKS for this... I've recently been dabbling in what I can do with utilizing the base java libraries and this is just slick!


Jul 9, 2008 at 7:30 PM // reply »
3 Comments

Heh, awesome. I spend five minutes refamiliarising myself with CF's built in randomizing functions in preparation for thinking through a solution to randomizing an array. Then on a whim I google it and BAM, first result, a solution in one line of code. I love CF - thanks Ben (and Mark)!


Jul 14, 2008 at 8:51 AM // reply »
10,638 Comments

@Kay,

Anytime :) Thanks for dropping by.


Nov 24, 2008 at 9:20 PM // reply »
1 Comments

Many thanks! Love your site!


Oct 6, 2010 at 8:57 PM // reply »
14 Comments

wowwwwwwwww! This cannot be easier!

This can be used to shuffle a list as well.

Put them into my framework ;-)

Thanks Ben and Mark.


Oct 10, 2010 at 4:07 PM // reply »
10,638 Comments

@Khoa,

Yeah, that Collections is pretty awesome. When Mark showed this to me, it totally blew my mind.


Dec 7, 2010 at 6:58 AM // reply »
3 Comments

Hmm.. I found that using an array of 5 elements or less causes repeats. E.g. aMy = [1,2,3,4,5]; shuffle(aMy); may return [1,1,4,4,5] or [1,2,2,3,5]...
If the array greater than 5 elements repeats doesn't occurs, just random sorting.


Dec 15, 2010 at 5:56 PM // reply »
10 Comments

@Ben,

Great post, thanks. And thanks Mark :)

@Alexey,

Why do you think this is the case. I tested with the following code and over 1000000 tries I never once got a duplicate.

  • for (var t=0; t lte 1000000; t=t+1) {
  • javaCollections = CreateObject( "java", "java.util.Collections");
  • lhs = createObject("java", "java.util.LinkedHashSet");
  • aMy = [1,2,3,4,5];
  • javaCollections.shuffle(aMy);
  • //remove duplicates
  • lhs.init( aMy );
  • aMy.clear();
  • aMy.addAll( lhs );
  • //still 5, if no dump
  • if (arrayLen(aMy) NEQ 5)
  • writeDump(aMy);
  • }
  • abort;


Dec 16, 2010 at 2:02 AM // reply »
3 Comments

@Curt
Thanks for your time! My fault, I accidentally misled you.
Correction: "I found that using an array of 4 elements or less causes
repeats. E.g. aMy = [1,2,3,4]; shuffle(aMy); may return [1,1,4,4] or [1,2,2,3]"


Dec 16, 2010 at 9:54 AM // reply »
10 Comments

@Alexey,

I ran the test with 4 items, 3 items, and 2 items in the array.

Curt


Dec 16, 2010 at 10:08 AM // reply »
3 Comments

I have a lot of duplicates using your code. Railo 3.2.005 (jdk 1.6.0_22). Bug maybe?


Dec 16, 2010 at 10:10 AM // reply »
10 Comments

Hmm, I ran mine against ACF 901. Maybe that is the difference. I will run it against my Railo and see what happens.

Thanks,
Curt


Dec 16, 2010 at 10:26 AM // reply »
10 Comments

Sure enough. It fails under Railo. Lots of duplicates.

Interesting. I wonder why? Java versions?

Good to know.

Thanks,
Curt


Jan 7, 2011 at 9:23 PM // reply »
10,638 Comments

@Alexey, @Curt,

Hmm, that is very curious. I haven't use Railo myself; but, since we are invoking a Java Collections explicitly (and not some CF class), you'd think that the behavior would be exactly the same. If anyone gets to the bottom of this, I'd be interested in hearing what it is.

Since I will assume the Java classes are the same (the Core java classes), I will assume that it has something to do with the Java class uses to implement the Array. Maybe there's a threading issue or something?


Apr 6, 2011 at 8:34 AM // reply »
211 Comments

Just an FYI: This was brought up on the Railo group recently. As soon as we get an answer from Micha, I'll post something here to clear it up. Someone suggested that it may be because Railo passes by reference, not by value.


Apr 6, 2011 at 9:05 AM // reply »
10 Comments

@Todd,

Sweet, thanks for the update Todd. Its funny because I hadn't really thought about this at all until yesterday and was just looking back into it.

Curt


Apr 6, 2011 at 10:41 AM // reply »
211 Comments

@Curt: Apparently this was a bug that was already fixed:
https://issues.jboss.org/browse/RAILO-1291


Apr 6, 2011 at 11:06 AM // reply »
1 Comments

First, we have solved the problem
https://issues.jboss.org/browse/RAILO-1291

Problem was the implementation of the method java.util.List#set(int, java.lang.Object), this method is never used by Railo, but supported because we have implemented the List interface for ArrayImpl (for compatibility reason) and of course the "shuffle" method use this method. the return value of the "set" method should be the element previously at the specified position, but railo has returned the object set to the array, like every set action in Railo does and because of that the failure was happening.

/micha

BTW: this has nothing to do with "pass-by-value", java does not know the "pass-by-value" concept for objects, this is just happening in ACF and to do so, ACF clones array before passing/returning to/from a UDF or assign to a variable, in this case ACF does not clone the array as well.


Apr 6, 2011 at 11:36 AM // reply »
10 Comments

@Michael and @Todd,

Sweet, Thanks for the update. I hadn't used it on Railo since I discovered this. Glad to know I can now. (I probably should have filed the bug for this, my bad).

Anyway, great work.

Curt


Apr 6, 2011 at 11:37 AM // reply »
211 Comments

@Curt: Slacker. ;)


Apr 7, 2011 at 7:38 AM // reply »
3 Comments

Kudos to the Railo guys for addressing this one so quickly.

If you want to use the Shuffle method in railo and like me either can't wait for the new release or are incapable of compiling the patch :-), the following work-around seems to work.

Basically it avoids using the railo Collections implementation by converting the CF Array to native Java objects, does the shuffle on those and then converts back to a CF Array again. It should work in both Adobe CF and Railo.

There may be a more efficient way to do the final conversion back to a CF array, but I'm only ever working with a list of 3 elements to be shuffled in my app :-)

<cffunction name="arrayShuffle" returntype="array">
<cfargument name="arrayIn" type="array">

<!--- NB: Only designed to work with single dimensioned arrays
--->

<cfset var jArrayList = CreateObject("java",
'java.util.ArrayList').init(arguments.arrayIn)>
<cfset var cfArray = ArrayNew(1)>
<cfset var objIterator = "">

<!--- Shuffle jArrayList --->
<cfset CreateObject(
"java",
"java.util.Collections"
).Shuffle(
jArrayList
) />

<!--- Now convert it back to a ColdFusion Array --->
<cfset objIterator = jArrayList.iterator()>
<cfloop condition="objIterator.hasNext()">
<cfset ArrayAppend(cfArray, objIterator.next())>
</cfloop>

<cfreturn cfArray>

</cffunction>


Apr 7, 2011 at 10:34 PM // reply »
10,638 Comments

@Michael,

Awesome stuff - you guys are so fast on the bug fixes. I am consistently impressed with your team!

@Andrew,

Cool stuff; but, the real question is - can you add the arrayShuffle() to the list of globally available functions of the language? I keep hear about how the Railo codebase can be programmatically extended. This seems like one of the coolest features.


Apr 7, 2011 at 10:46 PM // reply »
3 Comments

Hey Ben - I actually wasn't aware of this, but it appears that you certainly can.

I just found a blog post describing how it's done if you don't mind me posting the link:

http://www.railo.ch/blog/index.cfm/2009/7/23/Railo-31-Building-your-own-BuiltInFunction


Sep 1, 2011 at 12:19 PM // reply »
4 Comments

This is awesome. Saved my bacon today. Or shuffled it anyway.



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 3, 2012 at 10:49 PM
How I Got Node.js Running On A Linux Micro Instance Using Amazon EC2
Wow this was really helpful! Only thing I would add is you need to update your .bash_profile after you edit the secure_path. This is what I did: $ . ~/.bash_profile Otherwise, NPM won't be found. ... read »
Feb 3, 2012 at 10:14 PM
Pushing Base64-Encoded Images Over HTML5 WebSockets With Pusher And ColdFusion
@Ben, Just wanted to let you know that pusher are soon to start limiting sizes on messages. This was the detail that came through in the Feb dispatch: "However, we will soon be limiting the s ... read »
Feb 3, 2012 at 5:05 PM
Regular Expressions Make CSV Parsing In ColdFusion So Much Easier (And Faster)
I tried using your RegEx in my C# program, but it was matching an extra empty-string at the end and so I would end up with an extra field that doesn't exist, so I changed it to this: (^|,)("(?: ... read »
Feb 3, 2012 at 3:47 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
Josh Cyr posted this on Twitter just a little bit ago. Thought it was appropriate. http://stackoverflow.com/questions/1619152/how-to-create-rest-urls-without-verbs/1619677#1619677 ... read »
Feb 3, 2012 at 2:28 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
@Michael, You definitely make a good point (and extra points for quoting movies - I love movies). When you use a return() statement to define the object's public API, it does provide a consistent a ... read »
Feb 3, 2012 at 2:04 PM
Changing The Execution Context Of Your Self-Executing Function Blocks In JavaScript
To quote Jurassic Park: "Just because you can doesn't mean you should". I completely, utterly disagree with the thought that this is more readable. Consider the current module pattern: if ... read »
Feb 3, 2012 at 1:10 PM
REST API Design Rulebook By Mark Masse
@Jordan, Yeah, WRML was created by Mark Masse (author of the book). I also found it to be a bit convoluted. I suppose it is intended to allow the Client to be able to programmaticaly respond to cha ... read »
Feb 3, 2012 at 1:08 PM
ColdFusion Supports HTTP Verbs PUT And DELETE (As Well As GET And POST)
@Jason, To be honest, I don't have good answers for that kinds of stuff. And, to the point, that is specifically why I *really* liked the REST API Design Rulebook by Mark Masse - he just cuts throu ... read »