Groovy collections vs My Current Thought Process

I have been a ColdFusion developer since before I can remember. What I have always loved about the language is that it made hard things really easy to do. Somewhere along the way though I think it lost some of this magic at the core of the language. Let’s take a look at a pretty trivial problem (but one that might come up often) and look at how we can solve it in both ColdFusion and Groovy.

Given a collection of names : print each name to screen and display a comma in between each name. Make sure to ommit the comma after the last name in the collection.

This doesn’t seem like that hard of a problem, lets take a stab at it. First we create an array of names. In our first attempt we decide to use a for in loop and loop over each name in the collection. During each iteration we print the name and a comma. The main glaring problem with this approach is that we are going to print a comma after the last element and that won’t solve the problem at hand.

So we move on to our next attempt. We decide to use a for loop so that we can have the index of item that we are printing out. We will print out the name and a comma except for the last item where will not print out the comma.

While this will work it isn’t a very clean solution. All this work to solve a pretty simple problem. Finally we do some looking around and remember these a special function in the language to accomplish this. ArrayToList will actually take an array and create a list with a delimiter. I could of actually left out the comma here as it is the default but I just wanted to make sure it was clear what was going on.

So I asked another dev to look at the same problem and he pretty much took the same thought process I did. I don’t know about you but I feel like I write more loops in ColdFusion than anything so its alway my first instinct. Unless you know ever function the language has to offer the solution may not of been apparent to you right away. Be honest, did arrayToList cross your mind before you got to the solution?

Now let’s look at the Groovy solution. I am pretty new to the language but one thing I have noticed is that working with collections is a joy to do. First lets look at the solution and then we will talk through our thought process. The join method will “join” each element in the list and separate them with the delimiter you provide.

So what is the difference. The difference here is the join() is a first class member function. This means that I can call it directly on the collection itself. I don’t need to start thinking about what functions are available to me and what the arguments are (and what order the come in) I just know that I can call a method to accomplish this. I know that if I want to iterate over the collection of data I can call

names.each()
names.eachWithIndex()

I know that if I am looking for something within the collection I can call

names.find()
names.findAll()

I know that if I need the size of the collection I can call

names.size()

Finally what about a scenario where you want to create a new array that holds the string length of each of our names. Our first thought again is we need to loop over the current collection and create a new one. To do so we need to initialize an empty array, loop over each name and then add a new element using a function that takes the array name and value.

In Groovy we again know that the collection has a 1st class function to do this using collect. This will return a new collection by manipulating the existing collection. This to me is a very clean and elegant solution.

I hope nobody gets the wrong impression about ColdFusion here because many of these same approaches are the same in many languages. I just wanted to point out how much I enjoy working with collections in Groovy. They make me think a different way when dealing with data and I am finding myself writing a lot more boring iteration loops these days.

Hi, I’m Dan Vega. I am a Software Engineer living just outside of one of my favorite places in the world, Cleveland Ohio. I am a self-taught programmer who firmly believes that you can accomplish anything in this life if you put your mind to it, roll up your sleeves and are willing to put in the work.

I have been writing software for over 17+ years now and I use my knowledge, passion, and influence to help other developers achieve their goals. I teach online and currently, have over 22,000 students.

When I am not writing software I have a number of things that really keep me busy. I love to read books, listen to podcasts and watch online courses. I have a real thirst for knowledge and it consumes me every single day of the week. I also love to run & lift heavy weights which keep me balanced throughout the week.

Please note: I reserve the right to delete comments that are offensive or off-topic.

  • Now that CF10 / Railo 4 bring closures to the table and that we have arrayEach() a lot of this gets easier in CFML. At cf.Objective() I showed stuff like this in JavaScript, Groovy and Clojure – then showed how to do the exact same thing in CFML, via a couple of simple helper functions, based on arrayEach() etc.

    arrayReduce( names, function( s, n ) { return s & ", " & n; } ); // concatenates names

    arrayMap( names, function( n ) { return len( n ); } ); // produces list of lengths

    The code is available on my Github account (and linked from the Polyglot talk blog post, back in May).

  • Jason Durham

    Railo actually trumps (IMO) all of the methods described above with something as simple as names.toList().

    However, it seems likely in the real world we’re going to want a space after the comma. ArrayToList doesn’t support that, so we’re forced into looping with CFML. Does Groovy allow you to have multiple delimiters?

  • Cristian Pop

    I don’t know much about the Cfml childhood by I think that the language pays tribute to VB style in attempt to compete with it.

  • In groovy you can write this names.collect { it.length() } in shorter way.

    ?def names = ["your", "elements", "in", "array"]
    assert names.collect { it.length() } == names*.length()?????????

  • Jason – ArrayToList can take just about any delimiter

    arrayToList(names, ", " ) // adds a space

    What do you mean by multiple delimiters? I am sure you could do something like this

    names.join(‘ $#%@ ‘)

  • Minor point: if you had no choice but to go with the looping route in CFML to build the list, you could start off with an empty string variable and use ListAppend with each iteration to build it (would negate the need to determine if the comma needed to be added at the end of each item save the last one).

  • Thanks Sean – Unfortunately I haven’t had much of a chance to play with 10 yet. We have been avoiding upgrading at work because of a major ehcache bug (that I think is resolved now).

    Anyways your solution will work but I still don’t think its a clean and easy approach. I still think I would be hunting the docs for that. I also like that I can use the same member functions for different types of collections in Groovy. I can use arr.each() or map.each() and they both help me iterate over that collection. I just think the API is a little cleaner.

  • @Dan, Railo allows arr.each() and map.each() – it allows all the typeFunc() global functions to be used as obj.func() for obj of the given type:

    arrayLen(myArr) == myArr.len()

    I agree the anon fn syntax is a little verbose compare to some other languages but, hey, you can’t even do this in Java yet! 🙂

  • @Dan @Jason if arrayToList() takes any delimiter then Railo should allow:

    names.toList( ", " ); // done!

  • Jason Durham

    Indeed it does Dan and Sean. I thought that was one of those quirky gotchas that bit me in the past. Shame on me for not testing first. 🙂

  • Sean – These functions arrayEach, arrayReduce and arrayEach.. Are they in ColdFusion 10 or are these helper functions that you wrote?

  • arrayEach() / structEach() are in CF10 / Railo 4 – the latter also allows myArr.each() and myStruct.each().

    arrayMap() and arrayReduce() etc are my code – as I said:

    "The code is available on my Github account (and linked from the Polyglot talk blog post, back in May)."

    Here’s the direct link to the code on Github:

    https://github.com/seancorfield/cfo2013/blob/master/polyglot/map.cfm

  • BTW, here’s the toList() example, run on Railo 4 via cflive.net:

    <cfscript>
    names = ["Dan","Sam","Lance","Brian","Todd","Joe","Scott"];
    writeOutput( names.toList( ", " ) );
    </cfscript>

    Output:

    Dan, Sam, Lance, Brian, Todd, Joe, Scott