My ColdFusion Weekly Podcast CFQuiz Answer

Posted March 26, 2007 at 2:08 PM by Ben Nadel

Tags: ColdFusion

Unfortunately, I did not win in the ColdFusion weekly podcast (congratulations Dan Vega), but I think I had a cool answer that ya'll might be interested in seeing. Here is their question (as taken from the ColdFusion weekly website):

Programming exercise! In CF (obviously) write a script that loops from 1 to 100 and outputs the numbers. When a number is a multiple of 3, output "ColdFusion" and a line break. When a number is a multiple of 5, output "Rocks" and a line break. When a number is a multiple of 3 and 5, output "ColdFusion Rocks" and a line break. Slickest solution wins!

I took a two pronged approach to this answer. The first is a simple index loop using CFLoop (just to satisfy the question). The second approach is a sweet-ass ColdFusion custom tag that actually utilizes the CFExit method="LOOP" attribute (heck yeah!).

Ok, so here's the simple answer:

  • <!--- Loop from 1 to 100. --->
  • <cfloop
  • index="intI"
  • from="1"
  • to="100"
  • step="1">
  •  
  • <!--- Output the line number. --->
  • #intI#.
  •  
  • <!--- Check to see if this is a multiple of 3. --->
  • <cfif NOT (intI MOD 3)>
  • ColdFusion
  • </cfif>
  •  
  • <!--- Check to see if this is a multilple of 5. --->
  • <cfif NOT (intI MOD 5)>
  • Rocks!
  • </cfif>
  •  
  • <!---
  • ASSERT: The above to CFIF statements will handle
  • cases were the number is BOTH a multiple of
  • 3 and of 5. No need to handle those seperately
  • (ie. MOD 15 is already being handled).
  • --->
  • <br />
  •  
  • </cfloop>

Ok, that's pretty basic. But, it's not that flexible. I then created a ColdFusion custom tag to make this more open ended and seriously upped the "cool" factor. Before we get into how it's done, let's look at how it is called:

  • !--- This can be run as a self-closing tag. --->
  • <cfmodule
  • template="cfweeklyloop.cfm"
  • from="1"
  • to="100"
  • step="1"
  • mod3="ColdFusion"
  • mod5="Rocks!"
  • />
  •  
  •  
  • <!---
  • Or it can be run as a tag that allows custom
  • output inbetween each line item.
  • --->
  • <cfmodule
  • template="cfweeklyloop.cfm"
  • from="1"
  • to="100"
  • step="1"
  • mod3="ColdFusion"
  • mod5="Rocks!">
  •  
  • <hr />
  •  
  • </cfmodule>

As you can see above, the custom tag (executed via CFModule) uses the attributes "mod3" and "mod5" to accomplish what was accomplished in the first CFLoop tag. Ok, so now, let's look at the code:

  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!---
  • Check to see which version of the tag we are executing.
  • We only care about validating the tag attributes on the
  • start tag, not on the end tag.
  • --->
  • <cfswitch expression="#THISTAG.ExecutionMode#">
  •  
  • <cfcase value="START">
  •  
  •  
  • <!--- Param tag attributes. --->
  • <cfparam
  • name="ATTRIBUTES.From"
  • type="numeric"
  • />
  •  
  • <cfparam
  • name="ATTRIBUTES.To"
  • type="numeric"
  • />
  •  
  • <cfparam
  • name="ATTRIBUTES.Step"
  • type="numeric"
  • default="1"
  • />
  •  
  •  
  • <!---
  • Validate the step value to make sure an
  • infinite loop will never take place.
  • --->
  • <cfif (ATTRIBUTES.Step EQ 0)>
  •  
  • <!--- This tag loop will never end. --->
  • <cfthrow
  • type="EXCEPTION"
  • message="Invalid Loop Parameters"
  • detail="The FROM value #ATTRIBUTES.From#, TO value #ATTRIBUTES.To#, and STEP value #ATTRIBUTES.Step# will result in an infinite loop."
  • />
  •  
  • </cfif>
  •  
  •  
  • <!--- Create a struct of mod value to check. --->
  • <cfset THISTAG.ModValues = StructNew() />
  •  
  • <!---
  • Loop over the tag attributes to find the
  • mod values. Remember, at the time of the tag
  • execution, we are not sure yet which MOD
  • attribute are actually being passed in. We
  • have to find them manually.
  • --->
  • <cfloop
  • item="strKey"
  • collection="#ATTRIBUTES#">
  •  
  • <!--- Check to see if this key matches the MOD patterns. --->
  • <cfif strKey.Matches(
  • JavaCast( "string", "(?i)MOD[\d]+" )
  • )>
  •  
  • <!---
  • This is a MOD value. We have to store
  • both the mod value and the resultant
  • output value into the struct.
  • --->
  • <cfset THISTAG.ModValues[ strKey.ReplaceFirst( "(?i)^MOD", "" ) ] = ATTRIBUTES[ strKey ] />
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  •  
  • <!---
  • Now that we have a structure that contains keys
  • and output values, we have to get the array of
  • keys. We want this key to be in smallest-value
  • first as these will be most likely to be output.
  • --->
  • <cfset THISTAG.ModKeys = StructKeyArray( THISTAG.ModValues ) />
  •  
  • <!--- Sort the keys. --->
  • <cfset ArraySort( THISTAG.ModKeys, "numeric", "ASC" ) />
  •  
  •  
  • <!---
  • Initialize the tag to have the index equal to
  • the FROM attribute. This is the index that will
  • keep track of our loop from iteration to
  • iteration.
  • --->
  • <cfset THISTAG.Index = ATTRIBUTES.From />
  •  
  • </cfcase>
  •  
  •  
  • <cfcase value="END">
  •  
  • <!---
  • If this is the first iteration, check to see
  • if we should even execute it.
  • --->
  • <cfif (
  • (THISTAG.Index EQ ATTRIBUTES.From)
  • AND
  • (
  • (
  • (ATTRIBUTES.Step GT 0) AND
  • (THISTAG.Index GT ATTRIBUTES.To)
  • )
  • OR
  • (
  • (ATTRIBUTES.Step LT 0) AND
  • (THISTAG.Index LT ATTRIBUTES.To)
  • )
  • )
  • )>
  •  
  • <!---
  • This tag is starting out of bounds.
  • Exit out of the tag. Try to kill any
  • generated output.
  • --->
  • <cfset THISTAG.GeneratedContent = "" />
  •  
  • <!--- Exit tag. --->
  • <cfexit method="EXITTAG" />
  •  
  •  
  • </cfif>
  •  
  • </cfcase>
  •  
  • </cfswitch>
  •  
  •  
  • <!---
  • ASSERT: If we have reached this point then we are
  • either in the START mode of the tag or we have
  • reached the END mode of the tag and we are definitely
  • going to execute the tag at least once (for the
  • given iteration).
  • --->
  •  
  • </cfsilent>
  •  
  •  
  • <!---
  • We only want the output stuff to happen in
  • the end tag.
  • --->
  • <cfif (THISTAG.ExecutionMode EQ "End")>
  •  
  • <cfoutput>
  •  
  • <!--- Output the index. --->
  • #THISTAG.Index#.
  •  
  • <!---
  • Loop over the possible MOD values that we
  • collected earlier in the tag.
  • --->
  • <cfloop
  • index="intMod"
  • from="1"
  • to="#ArrayLen( THISTAG.ModKeys )#"
  • step="1">
  •  
  • <!---
  • Check to see if this key MODs evenly into
  • the current iteration index.
  • --->
  • <cfif NOT (THISTAG.Index MOD THISTAG.ModKeys[ intMod ])>
  •  
  • <!---
  • We have a match. Output the value
  • stored at this mod key.
  • --->
  • #THISTAG.ModValues[ THISTAG.ModKeys[ intMod ] ]#
  •  
  • </cfif>
  •  
  • </cfloop>
  •  
  • <!--- Line break. --->
  • <br />
  •  
  • </cfoutput>
  •  
  •  
  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!--- Increment the tag index. --->
  • <cfset THISTAG.Index = (THISTAG.Index + ATTRIBUTES.Step) />
  •  
  •  
  • <!---
  • Check to see which direction we are going in in
  • the loop and if we can increment. If we can, then
  • loop to the beginning of the tag.
  • --->
  • <cfif (
  • (
  • (ATTRIBUTES.Step GT 0) AND
  • (THISTAG.Index LTE ATTRIBUTES.To)
  • )
  • OR
  • (
  • (ATTRIBUTES.Step LT 0) AND
  • (THISTAG.Index GTE ATTRIBUTES.To)
  • )
  • )>
  •  
  • <!---
  • We still have more interations to perform. This
  • will break out of the current tag execution an
  • re-execute the tag keeping the same tag variables
  • in place.
  • --->
  • <cfexit method="LOOP" />
  •  
  • <cfelse>
  •  
  • <!--- We must end the loop. --->
  • <cfexit method="EXITTAG" />
  •  
  • </cfif>
  •  
  • </cfsilent>
  •  
  • </cfif>

So there you go. It was a lot of fun to write this and I was totally excited to finally get to use the LOOP directive for the CFExit tag - it's not often that that is useful. Plus, you can add any MODX attributes to the tag you want (where X is some integer).

I have been a long time listener to the ColdFusion weekly podcast and now, I am finally a participant. I may have lost this battle, but the next one is mine!




Reader Comments

Mar 26, 2007 at 4:11 PM // reply »
111 Comments

Hey Ben, Congrats on rewriting Fizzbuzz:
http://www.pbell.com/index.cfm/2007/3/13/Unit-Tests-for-Fizzbuzz
A little long, but at least you didn't add unit tests (check out the saga link - there is SUCH a back story to this thang).

My hack was:
http://www.pbell.com/index.cfm/2007/3/13/FizzBuzz-in-CF


Mar 26, 2007 at 4:21 PM // reply »
11,243 Comments

Oh dear lord! Why are there like 275+ comments on that post :D That is nuts. Well, the guys on CFWeekly said they got the question off of some other pod cast - perhaps it was one that was talking about this FizzBuzz stuff.


Mar 26, 2007 at 7:48 PM // reply »
51 Comments

Ben,
Thanks for the mention! I just went for the quick and easy solution.


Mar 26, 2007 at 9:31 PM // reply »
11,243 Comments

Yeah, but you used CSS and HTML :) I did not! You're the better man this time, Vega.


Mar 28, 2007 at 9:58 PM // reply »
6 Comments

What about:

<code>
<pre>
<cfscript>

for (a=1; a lte 100; a=a+1) {
writeoutput('<br>#numberformat(a,'000')# ');
modMe(a,3,' Coldfusion');
modMe(a,5,' Rocks');
}

function modMe(number,modno,message) {
if ( arguments.number mod arguments.modno eq 0 ) {
writeoutput(arguments.message);
}
return true;
}

</cfscript>
</pre>
</code>


Mar 29, 2007 at 7:33 AM // reply »
11,243 Comments

@Chris,

That would definitely work.


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
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 22, 2013 at 5:35 PM
Script Tags, jQuery, And Html(), Text() And Contents()
This is still an issue 2 years later. jQuery is supposed to remediate these cross browser issues, no? I have been unable to find any statement from the jQuery team calling this behavior "by de ... read »
May 22, 2013 at 12:44 PM
Ask Ben: Query Loop Inside CFScript Tags
In cf10, if you call a function that has: local.result = {}; local.result.msg = ""; local.svc = new query(); local.svc.setSQL("SELECT * FROM..."); local.obj = local.svc.exe ... read »
May 22, 2013 at 12:29 PM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Ben: What version of Java are you using? Also, did you test users.id to see what Java reports as the data type? I wonder if it's not a Java primitive data type, but getting returned as something ... read »
May 22, 2013 at 11:47 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Dana, Awesome - so it looks like this bug was fixed in ColdFusion 10. Thanks so much for double-checking that. ... read »
May 22, 2013 at 11:37 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
When I c&p and run on cf10, I get: Selected User IDs: 1,4 User 1 selected: YES - YES User 2 selected: NO - NO User 3 selected: NO - NO User 4 selected: YES - YES User 5 selected: NO - ... read »
May 22, 2013 at 11:27 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
@Tom, Good thought, but no dice. Both of these still exhibit the same behavior: users.id[ users.currentRow ] users[ "id" ][ users.currentRow ] It's just something whacky happening with ... read »
May 22, 2013 at 11:07 AM
Strange Interaction Between DeserializeJson(), ArrayContains(), And Database Values In ColdFusion
Could your problem be that "users.id" is actually an ARRAY, not a single value? Perhaps try it again with "users.id[1]" (I only have CF8 here at work). ... read »
May 22, 2013 at 7:52 AM
Nested Views, Routing, And Deep Linking With AngularJS
Hi, Just a quick thank you. As it happens, for my own purposes, the pending ui-router work being done in native angular is likely the one I'll adopt, but your exploration, code and documentation of ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools