The 12 Days of Christmas… or any countdown song


Loops are a big part of programming, because one of the benefits of programs is that they can automate repetitive tasks for humans. If we were to type out the complete lyrics to “The 12 Days of Christmas,” we would end up having to do a lot of typing! And it wouldn’t be fun typing—it would be boring, repetitive typing.

What about if you were to tell someone the lyrics to “The 12 Days of Christmas”? How would you describe it without repeating yourself? That’s pretty much how this program works.

So if I were to describe in English how to sing the song, I would say “There are 12 days. Each day has its own set of gifts for that day. You start with the gifts for the 1st day. Then you go to the 2nd and say the gifts for the 2nd day and the 1st day. Then you keep going to the 3rd day and 4th day all the way until the 12th day, when you count down all the gifts until you get back down to the 1st day.” Even that would be a bit confusing. Fortunately, there are easier ways to give the instructions in Python.

I’m going to give you a bunch of code to type in (yes, as always better to retype than copy/paste if you can), but I’m also going to explain along the way what’s happening:


# Create a list of the set of gifts for each day
days_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"
    ]

Let’s start with a simple loop to go through each of the days from the 1st day to the 12th day:


days_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"
    ]

def main():
    for gift in days_gifts:
        day_index = days_gifts.index(gift)
        print(f"\nOn the {day_index} day of Christmas, my true love gave to me...")
        print(gift)

if __name__ == "__main__":
    main()

If you run that and all goes well, you should see 12 days of Christmas and what was given on each day, but the numbers are a bit off. The 1st day will be marked 0, and the last day will be marked 11. That’s because the “index” of items in a list starts with 0 and not with 1.

We can fix that by adding 1 to each index number before printing it.

days_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"
    ]

def main():
    for gift in days_gifts:
        day_index = days_gifts.index(gift)
        day =  day_index + 1
        print(f"\nOn the {day} day of Christmas, my true love gave to me...")
        print(gift)

if __name__ == "__main__":
    main()

The issue here now is that the numbers are just numbers (1, 2, 3, 4, etc.) instead of ordinals (1st, 2nd, 3rd, 4th, etc.). We can fix that by adding in a function to “convert” numbers to ordinals.

days_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"
    ]

def ord_from_day_num(day_num):
    if day_num == 1:
        ord_day = str(day_num) + 'st'
    elif day_num == 2:
        ord_day = str(day_num) + 'nd'
    elif day_num == 3:
        ord_day = str(day_num) + 'rd'
    else:
        ord_day = str(day_num) + 'th'
    return ord_day

def main():
    for gift in days_gifts:
        day_index = days_gifts.index(gift)
        day =  day_index + 1
        print(f"\nOn the {ord_from_day_num(day)} day of Christmas, my true love gave to me...")
        print(gift)

if __name__ == "__main__":
    main()

At this point, we’re just listing the days. We aren’t counting down the days from each day back down to the 1st day. To do that, we’ll have to add in a while loop within our for loop:


days_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"
    ]

def ord_from_day_num(day_num):
    if day_num == 1:
        ord_day = str(day_num) + 'st'
    elif day_num == 2:
        ord_day = str(day_num) + 'nd'
    elif day_num == 3:
        ord_day = str(day_num) + 'rd'
    else:
        ord_day = str(day_num) + 'th'
    return ord_day

def main():
    for gift in days_gifts:
        day_index = days_gifts.index(gift)
        day =  day_index + 1
        print(f"\nOn the {ord_from_day_num(day)} day of Christmas, my true love gave to me...")
        print(gift)
        current_index = day_index - 1
        while current_index >= 0:
            print(days_gifts[current_index])
            current_index -= 1

if __name__ == "__main__":
    main()

This is basically taking whatever number we’re on (say, 5 for the 4th day) and subtracting 1 from it (so, then 4 for the 3rd day), and then printing out the gift for that day, and then subtracting more and more until we get to 0.

The only last tweak we need to do is add in an and for the last day:


days_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"
    ]

def ord_from_day_num(day_num):
    if day_num == 1:
        ord_day = str(day_num) + 'st'
    elif day_num == 2:
        ord_day = str(day_num) + 'nd'
    elif day_num == 3:
        ord_day = str(day_num) + 'rd'
    else:
        ord_day = str(day_num) + 'th'
    return ord_day

def main():
    for gift in days_gifts:
        day_index = days_gifts.index(gift)
        day =  day_index + 1
        print(f"\nOn the {ord_from_day_num(day)} day of Christmas, my true love gave to me...")
        print(gift)
        current_index = day_index - 1
        while current_index >= 0:
            if day_index != 0 and current_index == 0:
                print('and')
            print(days_gifts[current_index])
            current_index -= 1

if __name__ == "__main__":
    main()

The script should now loop through all the days in order and then count down from each one. Try it out!


Leave a Reply

Your email address will not be published.