Selecting The Seven Languages In Seven Weeks Winners
Posted February 10, 2011 at 10:14 AM by Ben Nadel
About a week or so ago, I finished working my way through Seven Languages in Seven Weeks by Bruce Tate. To celebrate my mostly triumphant reading of the book (shakes fist at Haskell, Day 3), I wanted to give away a few copies. But, in order to select the winners of the book, I wanted to have a little fun and try to play with the Mapping concepts that were often discussed within the book.
Given an array of players (those that submitted sample code on my wrap-up), I created an ArrayMap() function and a function that would randomly return a given value. The idea was to continue to reduce the collection of players until only 2 were left.
- <!--- Set up the array of players. --->
- <cfset players = [
- "Wilkins",
- "Mike",
- "Seth Stone",
- "Guganeshan.T",
- "Joshua Caito",
- "Joe Zack",
- "Andrew",
- "Rich",
- "Hidde-Jan",
- "dotnetCarpenter",
- "Adam Coffman",
- "Owen Pellegrin",
- "Ross Pfahler",
- "Marty",
- "Jared Cacurak",
- "Morten",
- "Greg Mefford",
- "Tracy Harms",
- "Eric Mitchell",
- "Jesse Riggins",
- "Danny Philayvanh",
- "Sharagoz",
- "Joel Neley",
- "Adam",
- "Nelle",
- "Matt Gutting",
- "Cade Cannon"
- ] />
-
-
- <!--- ----------------------------------------------------- --->
- <!--- ----------------------------------------------------- --->
-
-
- <!---
- Define a map function that maps one array onto another using
- the given function. When mapping, the following values will be
- handles as such:
-
- - Array - will be flattened and merged into the resultant array.
- - Value - will be added to the resultant array.
- - VOID - will not be added ot the resultant array.
- --->
- <cffunction
- name="arrayMap"
- access="public"
- returntype="array"
- output="false"
- hint="I map one array onto another array.">
-
- <!--- Define arguments. --->
- <cfargument
- name="originalArray"
- type="array"
- required="true"
- hint="I am the array being mapped."
- />
-
- <cfargument
- name="mapper"
- type="any"
- required="true"
- hint="I am the function used to perform the mapping."
- />
-
- <!--- Define the local scope. --->
- <cfset var local = {} />
-
- <!--- Define an array to hold the results of the mapping. --->
- <cfset local.results = [] />
-
- <!--- Loop over the array so we can map each value. --->
- <cfloop
- index="local.originalValue"
- array="#arguments.originalArray#">
-
- <!--- Hand this value off to the mapper function. --->
- <cfset local.mappedValue = arguments.mapper(
- local.originalValue
- ) />
-
- <!---
- Check to make sure that a value exists. If it doesn't,
- it means that VOID was returned; as such, no mapped
- value will be added to the results.
- --->
- <cfif structKeyExists( local, "mappedValue" )>
-
- <!---
- We know we have a mapped value, so let's not figure
- out how we are merging it into the results array.
- Arrays will be flattened; single values will be
- added as such.
- --->
- <cfif isArray( local.mappedValue )>
-
- <!--- Add each value of the array individually. --->
- <cfloop
- index="local.mappedSubValue"
- array="#local.mappedValue#">
-
- <!--- Add the flattened values. --->
- <cfset arrayAppend(
- local.results,
- local.mappedSubValue
- ) />
-
- </cfloop>
-
- <cfelse>
-
- <!--- Simply add the returned value. --->
- <cfset arrayAppend(
- local.results,
- local.mappedValue
- ) />
-
- </cfif>
-
- </cfif>
-
- </cfloop>
-
- <!--- Return the resultant array. --->
- <cfreturn local.results />
- </cffunction>
-
-
- <!--- ----------------------------------------------------- --->
- <!--- ----------------------------------------------------- --->
-
-
- <!---
- Now that we have our map function defined, we need to create a
- function that actually provides the mapping logic. For our
- purposes, we're going to keep mapping the players array onto a
- new array until we only have 2 people left. That means that our
- mapper function will be popping people out of the collection.
- --->
- <cffunction
- name="returnRandom"
- access="public"
- returntype="any"
- output="false"
- hint="I randomly return the given value or VOID.">
-
- <!--- Define arguments. --->
- <cfargument
- name="value"
- type="any"
- required="true"
- hint="I am the value being returned (maybe!)."
- />
-
- <!---
- Randomly decide to return this value or not. If it is
- returned, it will be mapped onto the results array; if it
- is not, it will be removed.
- --->
- <cfif (rand() gt .25)>
-
- <!--- Return the given value. --->
- <cfreturn arguments.value />
-
- <cfelse>
-
- <!--- Return void. --->
- <cfreturn />
-
- </cfif>
- </cffunction>
-
-
- <!--- ----------------------------------------------------- --->
- <!--- ----------------------------------------------------- --->
-
-
- <!---
- Now that we have all of our mapping functions in place, let's
- reduce our players collection down to a collection of 2. As we
- map, there is a chance that we will drop below 2. In that case,
- we'll have to just start over again.
- --->
- <cfoutput>
-
-
- <!---
- Keep looping until we stop. If we get a collection of 2,
- we will execute an explicit Break command.
- --->
- <cfloop condition="true">
-
- <!--- Copy our players array (set by VALUE). --->
- <cfset winners = players />
-
-
- <!--- Output the staring length. --->
- Starting Length: #arrayLen( winners )#<br />
-
-
- <!---
- Keep reducing the collection until it is less than
- or equal to 2 (we are hoping it is 2).
- --->
- <cfloop condition="(arrayLen( winners ) gt 2)">
-
- <!--- Reduce the collection randomly. --->
- <cfset winners = arrayMap(
- winners,
- returnRandom
- ) />
-
- <!--- Output the new length. --->
- Current Length: #arrayLen( winners )#<br />
-
- </cfloop>
-
-
- <!--- Check to see if the collection contains 2 values. --->
- <cfif (arrayLen( winners ) eq 2)>
-
- <!---
- We have reduced properly. Stop the reduction loop
- as we have found our winners.
- --->
- <cfbreak />
-
- </cfif>
-
- </cfloop>
-
-
- <hr />
-
- <!--- Output the winners. --->
- Winner: #winners[ 1 ]#<br />
- Winner: #winners[ 2 ]#<br />
-
- </cfoutput>
Since the reduction mapping might result in an array of length less than 2, I had to continually loop until the final array contained exactly two elements. When I ran the above code, I got the following page output:
Starting Length: 27
Current Length: 18
Current Length: 15
Current Length: 13
Current Length: 11
Current Length: 11
Current Length: 5
Current Length: 3
Current Length: 3
Current Length: 1
Starting Length: 27
Current Length: 21
Current Length: 16
Current Length: 10
Current Length: 8
Current Length: 8
Current Length: 7
Current Length: 7
Current Length: 7
Current Length: 5
Current Length: 1
Starting Length: 27
Current Length: 22
Current Length: 21
Current Length: 13
Current Length: 10
Current Length: 6
Current Length: 6
Current Length: 5
Current Length: 5
Current Length: 3
Current Length: 3
Current Length: 2
-------------------------------------------------
Winner: Jared Cacurak
Winner: Matt Gutting
As you can see, the reduction mapping had to run 3 times before it ended up with an array of length 2. Of course, I know there are much more efficient ways of doing this; but, efficiency wasn't really the point - I just wanted to have some fun with it.
Congratulations to Jared and Matt! You're about to get seven languages deep!
Reader Comments
Stupid ColdFusion!
I thought the point of your blog was to make me like ColdFusion, now I am not so sure it will every happen :)
/A Loser
@Morten,
Ha ha ha, the silver-lining to all of this is that if you use ColdFusion, you're already a winner :P
Feels good to see the name 'inside' coldfusion code ^_^
Congrats to winners.
@Guganeshan,
Thanks for participating my friend :)
Grats to the winners!
Thanks again for your creativity with the contest Ben. It would be cool to do something like this every once in a while even if there is no prize involved :)
@Andrew,
Always a pleasure to get smart people involved in good conversation :)
@Ben: Your mom is very informative. Thanks.
;)
@Todd,
Ha ha ha, well played :)



