I was looking around for an easy way to split lists of items into columns in a way that the number of items in each column would be less than or equal to the number of items in the first column. This prevents a final column with several more items than the others.
I came across an old post from Annie Mullin that established a templatetag to do this using a generator. I liked the idea, but felt that a templatetag was too unwieldy - a filter would be simpler and easier to use in a template. So, I turned it into one:
:::python
@register.filter
def columns(lst, cols):
"""
Break a list into ``n`` lists, typically for use in columns.
>>> lst = range(10)
>>> for list in columns(lst, 3):
... list
[0, 1, 2, 3]
[4, 5, 6]
[7, 8, 9]
"""
try:
cols = int(cols)
lst = list(lst)
except (ValueError, TypeError):
raise StopIteration()
start = 0
for i in xrange(cols):
stop = start + len(lst[i::cols])
yield lst[start:stop]
start = stop
This is then used in a template like this:
:::html+django
{% for column in list|columns:"3" %}
<ul>
{% for item in column %}
<li>
<a href="{{ item.get_absolute_url }}">{{ item }}</a>
</li>
{% endfor %}
</ul>
{% endfor %}