A variation of FizzBuzz, this challenge tests your ability to output or style things in different ways based on a recurring indexing pattern using Twig.
In FizzBuzz, counting from 1 to 100, you replace the number each time you encounter a multiple of 3 with “Fizz”, a multiple of 5 with “Buzz” and a multiple of both 3 and 5 with “FizzBuzz”. So the result is:
1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, ...
The challenge is to write a twig macro called “fizzBuzz” that will accept 3 parameters: entries
(an array of entries), fizz
(an array of integers) and buzz
(also an array of integers). The macro should output the titles of each of the provided entries as header tags with a class of “fizz” each time a multiple of one or more of the integers in the fizz
array is encountered, “buzz” each time a multiple of or more one of the integers in the buzz
array is encountered, and “fizzbuzz” each time a multiple of one or more of the integers in both the fizz
and buzz
arrays is encountered. So for example, calling:
{% set entries = craft.entries.limit(22).all() %}
{{ fizzBuzz(entries, [3, 7], [5, 17]) }}
Should output:
<h4 class="">Entry Title 1</h4>
<h4 class="">Entry Title 2</h4>
<h4 class="fizz">Entry Title 3</h4>
<h4 class="">Entry Title 4</h4>
<h4 class="buzz">Entry Title 5</h4>
<h4 class="fizz">Entry Title 6</h4>
<h4 class="fizz">Entry Title 7</h4>
<h4 class="">Entry Title 8</h4>
<h4 class="fizz">Entry Title 9</h4>
<h4 class="buzz">Entry Title 10</h4>
<h4 class="">Entry Title 11</h4>
<h4 class="fizz">Entry Title 12</h4>
<h4 class="">Entry Title 13</h4>
<h4 class="fizz">Entry Title 14</h4>
<h4 class="fizzbuzz">Entry Title 15</h4>
<h4 class="">Entry Title 16</h4>
<h4 class="buzz">Entry Title 17</h4>
<h4 class="fizz">Entry Title 18</h4>
<h4 class="">Entry Title 19</h4>
<h4 class="buzz">Entry Title 20</h4>
<h4 class="fizz">Entry Title 21</h4>
<h4 class="">Entry Title 22</h4>
The macro must output the tags with the appropriate classes given the 3 parameters as described above. It should not rely on any plugins and the code will be evaluated based on the following criteria in order of priority:
Therefore the code should be readable and easy to understand. It should be concise and non-repetative, but not at the expense of readability. It should be performant, but not at the expense of readability or brevity.
fizz
and buzz
parameters as integers. {% set entries = [] %}
{% set entry = craft.entries.one() %}
{% for i in 1..100 %}
{% set entries = entries|merge([entry]) %}
{% endfor %}
Being the first challenge, I was astounded by the number and quality of solutions that were submitted. Thank you to everyone who took part in the challenge, regardless of whether you submitted a solution or not. Hopefully you had fun and learned something along the way!!
To get us started, let’s look at how we might solve the challenge with fizz
and buzz
provided as integers rather than arrays.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i = loop.index %}
{% set fizzClass = '' %}
{% set buzzClass = '' %}
{% if i is divisible by(fizz) %}
{% set fizzClass = 'fizz' %}
{% endfor %}
{% if i is divisible by(buzz) %}
{% set buzzClass = 'buzz' %}
{% endfor %}
<h4 class="{{ fizzClass ~ buzzClass }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Josh Magness.
We’ve looped through the entries and for each loop index i
, we check if i
is divisible by fizz
and buzz
, updating the appropriate class if it is. Finally, we output the header class by concatenating fizzClass
and buzzClass
.
We use the divisible by operator to check if the integer i
is divisible by the integer fizz
. This can also be done using the modulo operator %
to check if the remainder equals 0
, but is perhaps less human readable than the method used above.
{% if i % fizz == 0 %}
{% set fizzClass = 'fizz' %}
{% endfor %}
Now let’s tackle the challenge of fizz
and buzz
being passed in as arrays. We’ll need to loop through each of them in order to determine whether the loop index i
is divisible by one or more of the values.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i = loop.index %}
{% set fizzClass = '' %}
{% set buzzClass = '' %}
{% for n in fizz %}
{% if i is divisible by(n) %}
{% set fizzClass = 'fizz' %}
{% endif %}
{% endfor %}
{% for n in buzz %}
{% if i is divisible by(n) %}
{% set buzzClass = 'buzz' %}
{% endif %}
{% endfor %}
<h4 class="{{ fizzClass ~ buzzClass }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: John Wells, Christian Seelbach, Craft CMS Berlin Meetup, Quentin Delcourt, Otto Radics.
This solution works well and is readable, but there is a potential performance hit as we loop through the entire fizz
and buzz
arrays regardless of whether the fizzClass
is empty or has been set. So for example, if i = 3
and fizz = [3, 7, 22]
then the following loop will be iterated over 3 times, unnecessarily checking if i
is divisible by n
each and every time:
{% for n in fizz %}
{% if i is divisible by(n) %}
{% set fizzClass = 'fizz' %}
{% endif %}
{% endfor %}
We could avoid this if there was a way to break out of a loop in Twig like in PHP, but there isn’t (it is possible with the Twig Perversion plugin). So instead, we can avoid this by adding a condition to the for loop, which will prevent the loop being entered as soon as fizzClass
has been set:
{% for n in fizz if not fizzClass %}
{% if i is divisible by(n) %}
{% set fizzClass = 'fizz' %}
{% endif %}
{% endfor %}
Resulting in a slightly more performant macro.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i = loop.index %}
{% set fizzClass = '' %}
{% set buzzClass = '' %}
{% for n in fizz if not fizzClass %}
{% if i is divisible by(n) %}
{% set fizzClass = 'fizz' %}
{% endif %}
{% endfor %}
{% for n in buzz if not buzzClass %}
{% if i is divisible by(n) %}
{% set buzzClass = 'buzz' %}
{% endif %}
{% endfor %}
<h4 class="{{ fizzClass ~ buzzClass }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Spenser Hannon.
This can also be achieved using a single array variable rather than 2 string variables to represent the classes.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i = loop.index %}
{% set classes = [] %}
{% for n in fizz if 'fizz' not in classes %}
{% if i is divisible by(n) %}
{% set classes = ['fizz'] %}
{% endif %}
{% endfor %}
{% for n in buzz if 'buzz' not in classes %}
{% if i is divisible by(n) %}
{% set classes = classes|merge(['buzz']) %}
{% endif %}
{% endfor %}
<h4 class="{{ classes|join('') }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Pierre Stoffe.
This can be further simplified to use a single string variable to represent the class.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i = loop.index %}
{% set class = '' %}
{% for n in fizz if 'fizz' not in class %}
{% if i is divisible by(n) %}
{% set class = 'fizz' %}
{% endif %}
{% endfor %}
{% for n in buzz if 'buzz' not in class %}
{% if i is divisible by(n) %}
{% set class = class ~ 'buzz' %}
{% endif %}
{% endfor %}
<h4 class="{{ class }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Trevor Plassman, Jason Sawyer.
This can be condensed by combining the set statements and the if statements, however this comes at the expense of readability.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i, class = loop.index, '' %}
{% for n in fizz if 'fizz' not in class and i is divisible by(n) %}
{% set class = 'fizz' %}
{% endfor %}
{% for n in buzz if 'buzz' not in class and i is divisible by(n) %}
{% set class = class ~ 'buzz' %}
{% endfor %}
<h4 class="{{ class }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Alex Roper, Henry Bley-Vroman.
You’ve probably noticed that the for loop over the elements in fizz
and buzz
are almost identical. We can avoid repeating ourselves by adding the fizz
and buzz
parameters to an associative array tests
and looping over that array, running our logic on each set of values
and using the key as the className
.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set i = loop.index %}
{% set class = '' %}
{% set tests = {'fizz': fizz, 'buzz': buzz} %}
{% for className, values in tests %}
{% for n in values if className not in class %}
{% if i is divisible by(n) %}
{% set class = class ~ className %}
{% endif %}
{% endfor %}
{% endfor %}
<h4 class="{{ class }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Paul Verheul, Steve Rowling.
Another way to avoid repeating ourselves is by adding a helper macro that will handle the logic for us and output the provided class
only if the number
is divisible by one or more of the integers in values
.
{% macro getClassIfDivisible(className, number, values) -%}
{% spaceless %}
{% set result = '' %}
{% for value in values if not result %}
{% if number is divisible by(value) %}
{% set result = className %}
{% endif %}
{% endfor %}
{{ result }}
{% endspaceless %}
{%- endmacro %}
Notice how we use the spaceless tag to remove whitespace within the block, as well as the whitespace control modifier to remove the leading (-%}
) and trailing ({%-
) whitespace between the macro tags.
We can then call our new getClassIfDivisible
macro as many times as we need to from within our fizzBuzz
macro, providing we first import it from _self
(assuming it exists in the same file).
{% macro fizzBuzz(entries, fizz, buzz) %}
{% from _self import getClassIfDivisible %}
{% for entry in entries %}
{% set i = loop.index %}
{% set class = '' %}
{% set class = class ~ getClassIfDivisible('fizz', i, fizz) %}
{% set class = class ~ getClassIfDivisible('buzz', i, buzz) %}
<h4 class="{{ class }}">{{ entry.title }} #{{ loop.index }}</h4>
{% endfor %}
{% endmacro %}
Similar solutions: Andrew Welch, Doug St. John, John F Morton, Patrick Harrington, Lindsey DiLoreto.
The solution above is analogous to creating a helper function in PHP which returns the result of a calculation that has to be performed multiple times.
There are of course many more possible solutions to the challenge. Oliver Stark, the evil genius, submitted this solution, which made me almost fall out of my chair with laughter when I saw it.
{% macro fizzBuzz(not, so, important) %}
<h4 class="">Entry Title 1</h4>
<h4 class="">Entry Title 2</h4>
<h4 class="fizz">Entry Title 3</h4>
<h4 class="">Entry Title 4</h4>
<h4 class="buzz">Entry Title 5</h4>
<h4 class="fizz">Entry Title 6</h4>
<h4 class="fizz">Entry Title 7</h4>
<h4 class="">Entry Title 8</h4>
<h4 class="fizz">Entry Title 9</h4>
<h4 class="buzz">Entry Title 10</h4>
<h4 class="">Entry Title 11>/h4>
<h4 class="fizz">Entry Title 12</h4>
<h4 class="">Entry Title 13</h4>
<h4 class="fizz">Entry Title 14</h4>
<h4 class="fizzbuzz">Entry Title 15</h4>
<h4 class="">Entry Title 16</h4>
<h4 class="buzz">Entry Title 17</h4>
<h4 class="fizz">Entry Title 18</h4>
<h4 class="">Entry Title 19</h4>
<h4 class="buzz">Entry Title 20</h4>
<h4 class="fizz">Entry Title 21</h4>
<h4 class="">Entry Title 22</h4>
{% endmacro %}
Finally, I would like to acknowledge the team effort and solution submitted by the Craft CMS Berlin Meetup team (Oliver, Mike, Kristian and Tom). While working on the solution, they stumbled upon a potential bug in Twig, which can be demonstrated as follows.
{% for entry in entries %}
{% for n in fizz %}
{{ loop.parent.loop.index }}-{{ loop.index }},
{% endfor %}
{% endfor %}
The code above should output 1-1, 1-2, 1-3,
and so on, but instead it throws an error with devMode
enabled and outputs a blank string otherwise. Referencing loop.index
in the outer loop, however, makes it work as expected.
{% for entry in entries %}
{% set i = loop.index %}
{% for n in fizz %}
{{ loop.parent.loop.index }}-{{ loop.index }},
{% endfor %}
{% endfor %}
The issue, as discovered and explained by Brad Bell, is as follows:
When the twig node visitor is parsing a for loop, they set the
with_loop
to false by default to determine ifloop
should be included in the context (source). But it looks like they’re only checking for the current loop, not for any nested loops (source), which would explain why it would work if you referenceloop
in the outer.
Thanks Brad, for putting out the fire that erupted in the slack channel. That was a blast!!
Solution submitted by Jason Sawyer on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set count = loop.index %}
{% set className = '' %}
{% for fiz in fizz if count is divisible by(fiz) %}
{% set className = 'fizz' %}
{% endfor %}
{% for buz in buzz if count is divisible by(buz) and className|length < 5 %}
{% set className = className ~ 'buzz' %}
{% endfor %}
<h4 class="{{ className }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Otto Radics on 11 November 2018.
{% macro fizzBuzz(entries, fizzArray, buzzArray) %}
{% for entry in entries %}
{% set fizzClass = null %}
{% set buzzClass = null %}
{% set mainIndex = loop.index %}
{# fizzArray #}
{% for fizzItem in fizzArray %}
{% if mainIndex is divisible by(fizzItem) %}
{% set fizzClass = 'fizz' %}
{% endif %}
{% endfor %}
{# buzzArray #}
{% for buzzItem in buzzArray %}
{% if mainIndex is divisible by(buzzItem) %}
{% set buzzClass = 'buzz' %}
{% endif %}
{% endfor %}
<h4 class="{{ fizzClass ?? null ~ buzzClass ?? null }}">
{{ entry.title }}
</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Josh Magness on 11 November 2018.
<style>
body{background:#282828;color:#fff}h1,h2,h3,h4,h5,h6{margin:1em}.fizz{color:#facb3e}.buzz{color:#75e5fa}.fizzbuzz{color:#fa67ee}
</style>
{% import _self as macro %}
{% set entries = range(1, 21) %}
{% macro fizzBuzz(entries) %}
{% for entry in entries %}
{% set variable = '' %}
{% if entry is divisible by(3) %}
{% set variable = 'fizz' %}
{% endif %}
{% if entry is divisible by(5) %}
{% set variable = 'buzz' %}
{% endif %}
{% if entry is divisible by(5) and entry is divisible by(3) %}
{% set variable = 'fizzbuzz' %}
{% endif %}
<h4 class="{{ variable }}">Entry Title {{ entry }}</h4>
{% endfor %}
{% endmacro %}
{{ macro.fizzBuzz(entries) }}
Solution submitted by Quentin Delcourt on 11 November 2018.
{% macro fizzBuzz(entries, fizzNumbers, buzzNumbers) %}
{%- for entry in entries -%}
{%- set entryIndex = loop.index -%}
{# Is it a "fizz" number? #}
{%- set isFizz = false -%}
{%- for fizzNumber in fizzNumbers -%}
{% set isFizz = isFizz or (entryIndex is divisible by(fizzNumber)) %}
{%- endfor -%}
{# Is it a "buzz" number? #}
{%- set isBuzz = false -%}
{%- for buzzNumber in buzzNumbers -%}
{% set isBuzz = isBuzz or (entryIndex is divisible by(buzzNumber)) %}
{%- endfor -%}
{# Determine the class to use #}
{%- set entryClass = (isFizz and isBuzz)
? 'fizzbuzz'
: (isFizz) ? 'fizz'
: (isBuzz) ? 'buzz'
: '' -%}
<h4 class="{{ entryClass }}">
{{- entry.title -}}
</h4>
{% endfor -%}
{% endmacro %}
Solution submitted by Henry Bley-Vroman on 11 November 2018.
{% macro fizzBuzz(items, fizzes, buzzes) %}
{% for item in items %}
{% set class = '' %}
{% set i = loop.index %}
{%- for fizz in fizzes if class != 'fizz' and i is divisible by(fizz) -%}
{% set class = 'fizz' -%}
{% endfor -%}
{% for buzz in buzzes if 'buzz' not in class and i is divisible by(buzz) -%}
{% set class = class ~ 'buzz' -%}
{% endfor -%}
<h4 class="{{ class }}">
{{- item.title -}}
</h4>
{% endfor %}
{% endmacro %}
{#
Note: I would prefer `<h4 {%- if class %} class="{{ class }}"{% endif %}>`,
but that doesn't meet challenge's requirements.
#}
Solution submitted by Alex Roper on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) %}
{%- for entry in entries %}
{%- set index, fizz, buzz = loop.index, null, null -%}
{%- for number in fizzes %}
{%- set fizz = index is divisible by(number) ? 'fizz' : fizz -%}
{% endfor -%}
{%- for number in buzzes %}
{%- set buzz = index is divisible by(number) ? 'buzz' : buzz -%}
{% endfor -%}
<h4 class="{{ fizz }}{{ buzz }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro fizzBuzz %}
Solution submitted by Craft CMS Berlin Meetup on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) %}
{% for entry in entries %}
{# We have to access loop.index here, otherwise loop.parent in child loops will have the wrong context. #}
{% set parentIndex = loop.index %}
{% set fizz = '' %}
{% set buzz = '' %}
{% for f in fizzes %}
{# This would work fine in pure Twig, but not in Craft: #}
{# set fizz = (loop.parent.loop.index % f == 0)? 'fizz': fizz #}
{# Instead, we'll use our parentIndex variable from above: #}
{% set fizz = (parentIndex % f == 0)? 'fizz': fizz %}
{% endfor %}
{% for b in buzzes %}
{# Same deal as above... #}
{% set buzz = (parentIndex % b == 0)? 'buzz': buzz %}
{% endfor %}
<h4 class="{{ fizz }}{{ buzz }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Pierre Stoffe on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set entryIndex = loop.index %}
{# Find out if entryIndex is a multiple of any integer from the fizz array #}
{% set fizzMultiples = [] %}
{% for int in fizz %}
{% if entryIndex is divisible by(int) %}
{% set fizzMultiples = fizzMultiples|merge([entryIndex]) %}
{% endif %}
{% endfor %}
{# Find out if entryIndex is a multiple of any integer from the buzz array #}
{% set buzzMultiples = [] %}
{% for int in buzz %}
{% if entryIndex is divisible by(int) %}
{% set buzzMultiples = buzzMultiples|merge([entryIndex]) %}
{% endif %}
{% endfor %}
{# Assign the relevant classes based on the arrays created above #}
{% set classes = [] %}
{% if entryIndex in fizzMultiples and entryIndex in buzzMultiples %}
{% set classes = classes|merge(['fizzbuzz']) %}
{% else %}
{% if entryIndex in fizzMultiples %}
{% set classes = classes|merge(['fizz']) %}
{% elseif entryIndex in buzzMultiples %}
{% set classes = classes|merge(['buzz']) %}
{% endif %}
{% endif %}
<h4 class="{{ classes|join(' ') }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Lindsey DiLoreto on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% from _self import addClass %}
{% for entry in entries %}
{% set f = addClass('fizz', fizz, loop.index)|trim %}
{% set b = addClass('buzz', buzz, loop.index)|trim %}
<h4 class="{{ f ~ b }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
{% macro addClass(class, numbers, index) %}
{% set output = '' %}
{% for num in numbers if index is divisible by(num) %}
{% set output = class %}
{% endfor %}
{{ output }}
{% endmacro %}
Solution submitted by Andrew Welch on 11 November 2018.
{#
# Challenge #1 – Putting the Fizz back in your Buzz
# https://craftcodingchallenge.com/challenge-1-putting-the-fizz-back-in-your-buzz
# @author Andrew Welch, nystudio107
#}
{#
# Return the value of `className` if `number` is a multiple of any of the values in the `values` array
# Otherwise, return an empty string
# @param int number
# @param int[] values
# @param string className
#}
{%- macro getClassIfMultiple(number, values, className) -%}
{% spaceless %}
{% set result = "" %}
{# Micro-optimization to not execute the loop if we already have set `result` #}
{% for value in values if not result %}
{% if number is divisible by(value) %}
{% set result = className %}
{% endif %}
{% endfor %}
{{ result }}
{% endspaceless %}
{%- endmacro -%}
{#
# Output each of the entry.title's with appropriate classes set depending on
# whether the index is a multiple of the numbers in fizz[] and buzz[]
# @param Entry[] entries
# @param int[] fizz
# @param int[] buzz
#}
{% macro fizzBuzz(entries, fizz, buzz) %}
{# Do the gruntwork via a reusable macro #}
{% from _self import getClassIfMultiple %}
{# Calculate the classes for each potential entry #}
{% for entry in entries %}
{% set fizzClass = getClassIfMultiple(loop.index, fizz, "fizz") %}
{% set buzzClass = getClassIfMultiple(loop.index, buzz, "buzz") %}
<h4 class="{{ fizzClass ~ buzzClass }}">{{ "#{entry.title} #{loop.index}" }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Patrick Harrington on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) -%}
{#- We'll be pulling in another macro so as not to be repeating ourselves too much. #}
{% import _self as macros %}
{%- for entry in entries %}
<h4 class="
{#- A couple of ternaries with whitespace control - and mocking having our other macro "return" a value -#}
{{- (macros.hasDivisibleNumber(entry.id, fizzes) == "true") ? 'fizz' }}
{{- (macros.hasDivisibleNumber(entry.id, buzzes) == "true") ? 'buzz' -}}
">
{{- entry.title ~ " " ~ entry.id -}}
</h4>
{% endfor %}
{% endmacro %}
{#- Checks to see if the given ID matches the rules of divisibility #}
{% macro hasDivisibleNumber(id, ints) -%}
{#- Mark as true if the ID actually exists in the array -#}
{%- set return = (id in ints) ? 'true' : '' -%}
{%- if return is empty -%}
{#- Only check keys that are less or half of the ID (otherwise they can't be divisors) -#}
{%- for int in ints if (int <= (id / 2)) -%}
{#- If cleanly divisible, mark as true -#}
{%- if id % int == 0 -%}
{%- set return = 'true' -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{#- Pseudo-return in Twig ;) -#}
{{- return -}}
{%- endmacro %}
Solution submitted by John F Morton on 11 November 2018.
{% macro divisibeByArray(mynumber, myarray) %}{% spaceless %}
{% set myreturn = 0 %}
{% for mydivider in myarray %}
{% if myreturn == 0 and mynumber is divisible by(mydivider) %}
{% set myreturn = myreturn + 1 %}
{% endif %}
{% endfor %}
{% if myreturn == 1%}
{{ myreturn }}
{% endif %}
{% endspaceless %}{% endmacro %}
{% macro fizzBuzz(allIntegers, fizzArray, buzzArray) %}
{% import _self as helpers %}
{% for myentry in allIntegers %}
{% set myclassname1 = helpers.divisibeByArray(myentry, fizzArray) ? 'fizz' : '' %}
{% set myclassname2 = helpers.divisibeByArray(myentry, buzzArray) ? 'buzz' : '' %}
{% set myclassname = myclassname1 ~ myclassname2 %}
{#<h4 class='{{ myclassname }}'>{{ myentry }} is {{ myclassname ? myclassname : 'nothing'}}</h4>#}
<h4 class='{{ myclassname }}'>Entry Title {{ myentry }}</h4>
{% endfor %}
{% endmacro %}
{% import _self as macros %}
Solution submitted by Spenser Hannon on 11 November 2018.
{% macro fizzBuzz(entries, fizzes, buzzes) %}
{%- for entry in entries -%}
{%- set fizz = '' -%}
{%- set buzz = '' -%}
{%- set n = loop.index -%}
{%- for f in fizzes -%}
{%- if fizz is empty -%}
{%- set fizz = (n % f == 0) ? 'fizz' : '' -%}
{%- endif -%}
{%- endfor -%}
{%- for b in buzzes -%}
{%- if buzz is empty -%}
{%- set buzz = (n % b == 0) ? 'buzz' : '' -%}
{%- endif -%}
{%- endfor -%}
<h4 class="{{ fizz }}{{ buzz }}">{{ entry }}</h4>
{%- endfor -%}
{% endmacro %}
Solution submitted by Doug St. John on 11 November 2018.
<html>
<head>
<title>craftcodingchallenge #1 | dstjohn</title>
<link type="text/css" rel="stylesheet" href="https://craftcodingchallenge.com/interface/css/fizzbuzz.css" />
</head>
<body>
{# Get entries list #}
{% set entries = [] %}
{% set entry = craft.entries.one() %}
{% for i in 1..100 %}
{% set entries = entries|merge([entry]) %}
{% endfor %}
{% import _self as self %}
{{ self.fizzBuzz(craft.entries.limit(22).all(), [3, 7], [5, 17]) }}
</body>
</html>
{# Generate output #}
{% macro fizzBuzz(entries, fizzIds, buzzIds) %}
{% import _self as self %}
{% for entry in entries %}
{% set class = [
self.checkDivisible(loop.index, fizzIds, 'fizz'),
self.checkDivisible(loop.index, buzzIds, 'buzz'),
]|join %}
<h4 class="{{ class }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
{# Return classString if loopIndex is divisible by one of the divisibleIds passed #}
{% macro checkDivisible(loopIndex, divisibleIds, classString) %}{% spaceless %}
{% set break = false %}
{% for id in divisibleIds if not break %}
{% if loopIndex is divisible by(id) %}
{{ classString }}
{% set break = true %}
{% endif %}
{% endfor %}
{% endspaceless %}{% endmacro %}
Solution submitted by Trevor Plassman on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{# Save outer loop index to variable for inner loop modulus calc #}
{% set i = loop.index %}
{# Start w/ empty class variable to add to #}
{% set class = '' %}
{# Check if current index is fizzy, but only once #}
{% set fizzy = false %}
{% for f in fizz if not fizzy %}
{% if i % f == 0 %}
{% set class = class ~ 'fizz' %}
{% set fizzy = true %}
{% endif %}
{% endfor %}
{# Check if current index is buzzy, but only once #}
{% set buzzy = false %}
{% for b in buzz if not buzzy %}
{% if i % b == 0 %}
{% set class = class ~ 'buzz' %}
{% set buzzy = true %}
{% endif %}
{% endfor %}
<h4 class="{{ class is not empty ? class }}">
{{ entry.title }}
</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Oliver Stark on 11 November 2018.
{% macro fizzBuzz(not, so, important) %}
<h4 class="">Entry Title 1</h4>
<h4 class="">Entry Title 2</h4>
<h4 class="fizz">Entry Title 3</h4>
<h4 class="">Entry Title 4</h4>
<h4 class="buzz">Entry Title 5</h4>
<h4 class="fizz">Entry Title 6</h4>
<h4 class="fizz">Entry Title 7</h4>
<h4 class="">Entry Title 8</h4>
<h4 class="fizz">Entry Title 9</h4>
<h4 class="buzz">Entry Title 10</h4>
<h4 class="">Entry Title 11>/h4>
<h4 class="fizz">Entry Title 12</h4>
<h4 class="">Entry Title 13</h4>
<h4 class="fizz">Entry Title 14</h4>
<h4 class="fizzbuzz">Entry Title 15</h4>
<h4 class="">Entry Title 16</h4>
<h4 class="buzz">Entry Title 17</h4>
<h4 class="fizz">Entry Title 18</h4>
<h4 class="">Entry Title 19</h4>
<h4 class="buzz">Entry Title 20</h4>
<h4 class="fizz">Entry Title 21</h4>
<h4 class="">Entry Title 22</h4>
{% endmacro %}
Solution submitted by Steve Rowling on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{% set classes = [] %}
{% set tests = {
'fizz': fizz,
'buzz': buzz
} %}
{% set number = loop.index %}
{% for key,test in tests %}
{% for int in test %}
{% if number is divisible by(int) and (classes|indexOf(key) == -1) %}
{% set classes = classes|merge([key]) %}
{% endif %}
{% endfor %}
{% endfor %}
<h4 class="{{ classes|join('') }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by Christian Seelbach on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{%- for entry in entries %}
{%- set index = loop.index %}
{%- set isFizz = false %}
{%- set isBuzz = false %}
{%- for int in fizz %}
{%- set isFizz = isFizz or index is divisible by(int) %}
{%- endfor %}
{%- for int in buzz %}
{%- set isBuzz = isBuzz or index is divisible by(int) %}
{%- endfor %}
{%- set classes = [
isFizz and not isBuzz ? 'fizz',
not isFizz and isBuzz ? 'buzz',
isFizz and isBuzz ? 'fizzbuzz',
]|filter|join(' ') -%}
<h4 class="{{ classes }}">{{ entry.title }}</h4>
{%- endfor -%}
{% endmacro %}
Solution submitted by Paul Verheul on 11 November 2018.
{% macro fizzBuzz(entries, fizz = [], buzz = []) %}
{% for entry in entries %}
{# safe the loop variable into a new one, to prevent interference with the next for-loop #}
{% set entryLoop = loop %}
{# set a base 'class' variable, to not have to worry about a default value later on #}
{% set class = '' %}
{#
# Loop through all fizzes and buzzes to check if we should add them.
# If we find a fizz or a buzz, break from our loop by setting the typeFound variable to true.
# We do it this way, to have the possibility of adding, for example, 'fuzz' by adding two lines of code.
#}
{% for type in ['fizz', 'buzz'] %}
{% set typeFound = false %}
{% for int in _context[type] if not typeFound %}
{% if entryLoop.index is divisible by(int) %}
{% set class = class ~ type %}
{% set typeFound = true %}
{% endif %}
{% endfor %}
{% endfor %}
<h4 class="{{ class }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}
Solution submitted by John Wells on 11 November 2018.
{% macro fizzBuzz(entries, fizz, buzz) %}
{% for entry in entries %}
{# The "loop" variable cannot be used in a looping condition #}
{% set index = loop.index %}
{# False by default #}
{% set isFizz = false %}
{% set isBuzz = false %}
{% for n in fizz if index is divisible by(n) %}
{% set isFizz = true %}
{% endfor %}
{% for n in buzz if index is divisible by(n) %}
{% set isBuzz = true %}
{% endfor %}
<h4 data-loop="{{ index }}" class="{{ isFizz ? 'fizz' }}{{ isBuzz ? 'buzz' }}">{{ entry.title }}</h4>
{% endfor %}
{% endmacro %}