Friday Challenge - Christmas Style

This post is more than 2 years old.

Last year I did a few Christmas style friday challenges, so I'm a bit overdue. This one is rather simple. Given a query that contains an ID, which corresponds to a day, and a gift, print out the famous "12 Days of Christmas" song dynamically. Ie, day 1 you get gift 1. Day 2 you get 1 of gift 1, and 2 of gift 2. And so on.

Bonus points if you use festive green and red fonts in your display. (Once again, this is why they don't let me design.)

Double bonus points if you make a cfpresentation out it and record MP3s to go along with it.

Here is your query that you must use with the code. (Note, it uses CF8 Array shorthand style. If you aren't on CF8, you can rewrite that as a list and use listToArray.)

<cfset song = querynew("id,gift","integer,varchar")>

<cfset gifts = ["A partridge in a pear tree","Two turtle doves","Three French hens","Four calling birds","Five golden rings","Six geese a-laying", "Seven swans a-swimming","Eight maids a-milking","Nine ladies dancing","Ten lords a-leaping","Eleven pipers piping","Twelve drummers drumming"]>

<cfloop index="x" from="1" to="#arrayLen(gifts)#"> <cfset queryAddRow(song)> <cfset querySetCell(song, "id", x)> <cfset querySetCell(song, "gift", gifts[x])> </cfloop>

Raymond Camden's Picture

About Raymond Camden

Raymond is a senior developer evangelist for Adobe. He focuses on document services, JavaScript, and enterprise cat demos. If you like this article, please consider visiting my Amazon Wishlist or donating via PayPal to show your support. You can even buy me a coffee!

Lafayette, LA https://www.raymondcamden.com

Archived Comments

Comment 1 by Gary Gilbert posted on 12/14/2007 at 8:15 PM

Hi Ray,

Here is my "solution". It's not elegant or pretty (thanks in part to the colors) but it works :). I loop through the query and through each loop I pass the query and the day a function which then loops through the function and outputs the song as its sung (in reverse).

<cffunction name="song2" output="true" >
<cfargument name="x" type="numeric" required="true">
<cfargument name="q" type="query" required="true">

<cfloop from="#x#" to="1" index="i" step="-1">
<cfoutput><span style="color:<cfif i mod 2 eq 0>red<cfelse>green</cfif>">#q.gift[i]#</span></cfoutput>
</cfloop>
</cffunction>

<cfoutput query="song">
On the #id# day of christmas my true love gave to me:
#song2(song.id,song)# <br>
</cfoutput>

Comment 2 by Gary Gilbert posted on 12/14/2007 at 8:16 PM

dang forgot to add the output :) Please delete it if you don't want it

On the 1 day of christmas my true love gave to me:
<span style="color:green">A partridge in a pear tree</span> <br>

On the 2 day of christmas my true love gave to me:
<span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 3 day of christmas my true love gave to me:
<span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 4 day of christmas my true love gave to me:
<span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 5 day of christmas my true love gave to me:
<span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 6 day of christmas my true love gave to me:
<span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 7 day of christmas my true love gave to me:
<span style="color:green">Seven swans a-swimming</span> <span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 8 day of christmas my true love gave to me:
<span style="color:red">Eight maids a-milking</span> <span style="color:green">Seven swans a-swimming</span> <span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 9 day of christmas my true love gave to me:
<span style="color:green">Nine ladies dancing</span> <span style="color:red">Eight maids a-milking</span> <span style="color:green">Seven swans a-swimming</span> <span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 10 day of christmas my true love gave to me:
<span style="color:red">Ten lords a-leaping</span> <span style="color:green">Nine ladies dancing</span> <span style="color:red">Eight maids a-milking</span> <span style="color:green">Seven swans a-swimming</span> <span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 11 day of christmas my true love gave to me:
<span style="color:green">Eleven pipers piping</span> <span style="color:red">Ten lords a-leaping</span> <span style="color:green">Nine ladies dancing</span> <span style="color:red">Eight maids a-milking</span> <span style="color:green">Seven swans a-swimming</span> <span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

On the 12 day of christmas my true love gave to me:
<span style="color:red">Twelve drummers drumming</span> <span style="color:green">Eleven pipers piping</span> <span style="color:red">Ten lords a-leaping</span> <span style="color:green">Nine ladies dancing</span> <span style="color:red">Eight maids a-milking</span> <span style="color:green">Seven swans a-swimming</span> <span style="color:red">Six geese a-laying</span> <span style="color:green">Five golden rings</span> <span style="color:red">Four calling birds</span> <span style="color:green">Three French hens</span> <span style="color:red">Two turtle doves</span> <span style="color:green">A partridge in a pear tree</span> <br>

Comment 3 by todd sharp posted on 12/14/2007 at 8:22 PM

<cfset song = querynew("id,gift","integer,varchar")>

<cfset gifts = ["A partridge in a pear tree","Two turtle doves","Three French hens","Four calling birds","Five golden rings","Six geese a-laying",
"Seven swans a-swimming","Eight maids a-milking","Nine ladies dancing","Ten lords a-leaping","Eleven pipers piping","Twelve drummers drumming"]>

<cfloop index="x" from="1" to="#arrayLen(gifts)#">
<cfset queryAddRow(song)>
<cfset querySetCell(song, "id", x)>
<cfset querySetCell(song, "gift", gifts[x])>
</cfloop>

<cfquery name="getSong" dbtype="query">
select *
from song
order by id desc
</cfquery>

<cfset title = "The 12 days of Christmas...">

<cfpresentation title="#title#">
<cfoutput query="getSong">
<cfsavecontent variable="slideTitle">On the #id#<cfif id eq 1>st<cfelseif id eq 3>rd<cfelseif id eq 2>nd<cfelse>th</cfif> day of Christmas my true love gave to me....</cfsavecontent>
<cfpresentationslide title="#slideTitle#">
<div>
<img src="christmas_lights.gif" /><br/>
<h1>#title#</h1>
<h2>#slideTitle#</h2>
<span>#getSong.gift#</span>
</div>
</cfpresentationslide>
</cfoutput>
</cfpresentation>

http://cfsilence.com/blog/d...

Comment 4 by todd sharp posted on 12/14/2007 at 8:23 PM

I couldn't find a suitable cheesy mp3 to go along...sorry...

Comment 5 by Raymond Camden posted on 12/14/2007 at 8:28 PM

Todd, your code doesn't work right. It starts with day 12. It should start with day 1. And on days 2-12, it doesn't show the previous gifts. Ie, day 2 should show day 1's gift as well.

Comment 6 by todd sharp posted on 12/14/2007 at 8:42 PM

you grinch...

how's this? http://cfsilence.com/blog/d...

Comment 7 by Dave Ferguson posted on 12/14/2007 at 9:02 PM

Here is my contribution. I wish I had time to do more with it. Maybe later today if I can find some free time.

<CFSET IMGRoot = "http://www.dkferguson.com/1...">
<cfset song = querynew("id,gift","integer,varchar")>
<cfset gifts = ["A partridge in a pear tree","Two turtle doves","Three French hens","Four calling birds","Five golden rings","Six geese a-laying",
"Seven swans a-swimming","Eight maids a-milking","Nine ladies dancing","Ten lords a-leaping","Eleven pipers piping","Twelve drummers drumming"]>

<cfloop index="x" from="1" to="#arrayLen(gifts)#">
<cfset queryAddRow(song)>
<cfset querySetCell(song, "id", x)>
<cfset querySetCell(song, "gift", gifts[x])>
</cfloop>

<CFOUTPUT>
<CFLOOP INDEX="d" FROM="1" TO="12">
<DIV ID="day#d#" STYLE="width:100%; float:left;">
<CFQUERY NAME="getGifts" DBTYPE="QUERY">
select * from song where id <= #d#
order by id desc
</CFQUERY>
<BR><BR>
ON DAY #d# of Christmas I got all this stuff:<BR>
<CFLOOP QUERY="getGifts">
<DIV ID="gift#d##id#" STYLE="float:left;">
<IMG SRC="#IMGRoot#/#id#.jpg">
</DIV>
</CFLOOP>
</DIV>
</CFLOOP>
</CFOUTPUT>

Comment 8 by Raymond Camden posted on 12/14/2007 at 9:04 PM

Guys, to save space, when you post code, don't duplicate the data stuff please.

Comment 9 by Rick O posted on 12/14/2007 at 9:13 PM

Just because I hadn't seen a QoQ solution yet, nor one that created grammatically correct sentences. ;-)

<cffunction name="Dayify" returntype="query">
<cfargument name="Q" type="query" required="true">
<cfset var Result="">
<cfset var P=arguments.q>
<cfset var R=arguments.q>
<cfquery dbtype="query" name="Result">
SELECT r.id AS daynum, p.id AS id, p.gift AS gift
FROM r, p
WHERE (r.id >= p.id)
ORDER BY 1, 2 DESC, 3
</cfquery>
<cfreturn Result>
</cffunction>
<cffunction name="htmlFromSong" returntype="string">
<cfargument name="Q" type="query" required="true">
<cfset var Verses=Dayify(Q)>
<cfset var Result="">
<cfset var Colors=listToArray("red,green")>
<cfset var Suffixes="st,nd,rd">
<cfif Verses.recordCount gt 3>
<cfset Suffixes=listAppend(Suffixes,repeatString("th,",Verses.recordCount-3))>
</cfif>
<cfset suffixes=listToArray(suffixes)>
<cfsavecontent variable="Result">
<cfoutput query="Verses" group="DayNum">
<p>On the #DayNum#<sup>#Suffixes[DayNum]#</sup> day of Christmas, my true love gave to me: <cfoutput><cfif DayNum neq id>, <cfif id eq 1>and </cfif></cfif><span style="color:#Colors[incrementValue(id MOD 2)]#">#HTMLEditFormat(gift)#</span></cfoutput>.</p>
</cfoutput>
</cfsavecontent>
<cfreturn Result>
</cffunction>

<cfoutput>#htmlFromSong(Song)#</cfoutput>

Comment 10 by Ron Gowen posted on 12/14/2007 at 9:13 PM

Never did cfpresentation before, thamks Todd :)

<cfset song = querynew("id,gift","integer,varchar")>

<cfset gifts = ["A partridge in a pear tree","Two turtle doves","Three French hens","Four calling birds","Five golden rings","Six geese a-laying",
"Seven swans a-swimming","Eight maids a-milking","Nine ladies dancing","Ten lords a-leaping","Eleven pipers piping","Twelve drummers drumming"]>

<cfloop index="x" from="1" to="#arrayLen(gifts)#">
<cfset queryAddRow(song)>
<cfset querySetCell(song, "id", x)>
<cfset querySetCell(song, "gift", gifts[x])>
</cfloop>

<cffunction name="ord" access="public" returntype="string" output="false">
<cfargument name="theNum" type="string" required="true" />
<cfset theNewNum = "" />
<cfswitch expression="#arguments.theNum#">
<cfcase value="1">
<cfset theNewNum = arguments.theNum &'st' />
</cfcase>
<cfcase value="2">
<cfset theNewNum = arguments.theNum &'nd' />
</cfcase>
<cfcase value="3">
<cfset theNewNum = arguments.theNum &'rd' />
</cfcase>
<cfdefaultcase>
<cfset theNewNum = arguments.theNum &'th' />
</cfdefaultcase>
</cfswitch>
<cfreturn theNewNum />
</cffunction>

<cfoutput>
<cfset title="The 12 Days of Christmas" />
<cfpresentation title="The 12 Days of Christmas - stole this part from Todd thx">

<cfloop from="1" to="12" index="i">
<cfset slideTitle = "On the #ord(i)# day of christmas my true love brought to me" />
<cfpresentationSlide title="#slideTitle#" duration="2">
<div>
#title#<br />
#slideTitle#
<br /><br />
<cfloop from="12" to="1" index="j" step="-1">

<cfif j LTE i>
<cfif j MOD 2>
<cfset fColor = 'green' />
<cfelse>
<cfset fColor = 'red' />
</cfif>
<cfif j EQ 5>
<span style="letter-spacing:2.5em; color:#fColor#;">#song.gift[j]#</span><br />
<cfelse>
<span style="color:#fColor#;">#song.gift[j]#</span><br />
</cfif>
</cfif>
</cfloop>
</div>
</cfpresentationSlide>
<br /><br />
</cfloop>

</cfpresentation>
</cfoutput>

Comment 11 by Shane Zehnder posted on 12/14/2007 at 9:22 PM

After seeing Todd playing around with the <cfpresentation> tag I am starting to like it more and more.

Looks like it can be very useful.

Comment 12 by todd sharp posted on 12/14/2007 at 9:28 PM

"nor one that created grammatically correct sentences"

Mine didn't do this?

Comment 13 by Mat Evans posted on 12/14/2007 at 9:53 PM

hehe i enjoyed that.. here's my code..

<cfscript>
function SingTheSong(level) {
if(level < 13) {
writeOutput('On the ' & level & ' day of christmas, my true love gave to me..<br>');
for(i = level; i neq 0; i=i-1){
if(i mod 2 gt 0){colour='red';} else {colour='green';}
writeOutput('&nbsp;&nbsp;<span style="color:' & colour & ';">' & song.gift[i] & '</span><br>');
}
SingTheSong(level+1);
}
}
</cfscript>

<cfoutput>
#SingTheSong(1)#
</cfoutput>

Comment 14 by Gareth posted on 12/14/2007 at 11:23 PM

I modified mine slightly to include first, second, etc.

<cfcomponent output="true">
<cfset this.gifts = ListToArray("A partridge in a pear tree,Two turtle doves and,Three French hens,Four calling birds,Five golden rings,Six geese a-laying,Seven swans a-swimming,Eight maids a-milking,Nine ladies dancing,Ten lords a-leaping,Eleven pipers piping,Twelve drummers drumming")>

<cfset this.days = ListToArray("first,second,third,fourth,fifth,sixth,seventh,eight,ninth,tenth,eleventh,twelfth")>

<cffunction name="down" access="remote" output="true" returntype="void">
<cfargument name="arrayPosition" default="1" />

#this.gifts[arguments.arrayPosition]#
<cfif arguments.arrayPosition gt 1>
, #down(arguments.arrayPosition-1)#
</cfif>
</cffunction>

<cffunction name="daysOfXmas" access="remote" output="true" returntype="void">
<cfloop from="1" to="12" index="eachDay">
On the #this.days[eachDay]# day of xmas, my true love gave to me<br>
#down(eachDay)#<br><br>
</cfloop>
</cffunction>
</cfcomponent>

Comment 15 by Simeon posted on 12/14/2007 at 11:48 PM

I decided to do mine in Ruby which really makes it ineligible for any contest but it was fun anyway :)

http://blog.simb.net/2007/1...

Technically the part that outputs the song is 8 lines of code.

Comment 16 by todd sharp posted on 12/14/2007 at 11:57 PM

RUBY???? Lifetime ban!!!!!!!!!!!! :D

Comment 17 by todd sharp posted on 12/15/2007 at 1:34 AM

Hey guys - check Ray's post about grabbing the img's from Yahoo.

I mashed that up with my stuff and randomized the results for each slide:

http://cfsilence.com/blog/d...

(Oh and for the cfpresentation fans - rather then re-create the preso on the fly I took advantage of the directory attribute and wrote it to disk)

Comment 18 by Fitz posted on 12/19/2007 at 4:39 AM

Hope I'm not to late to get in on the fun!

<div style="width: 400px; font: .9em/1.8em Georgia, 'Times New Roman', Times, serif; padding: 30px;">
<cfoutput>
<cfloop from="1" to="#arrayLen(gifts)#" index="j">
<div style="padding: 20px 0; border-bottom: 1px solid ##ccc; color: green;">
<em style="color: red;">On the #j# day of Christmas, my true love gave to me,</em><br />
<cfloop from="#j#" to="1" index="k" step="-1">
<cfif (j gte 2 and k eq 1)>
and
</cfif>
#song.gift[k]#<br />
</cfloop>
</div>
</cfloop>
</cfoutput>
</div>