""" Template filters to partition lists into rows or columns. A common use-case is for splitting a list into a table with columns:: {% load partition %} {% for row in mylist|columns:3 %} {% for item in row %} {% endfor %} {% endfor %}
{{ item }}
""" from django.template import Library register = Library() def rows(thelist, n): """ Break a list into ``n`` rows, filling up each row to the maximum equal length possible. For example:: >>> l = range(10) >>> rows(l, 2) [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] >>> rows(l, 3) [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9]] >>> rows(l, 4) [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]] >>> rows(l, 5) [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]] >>> rows(l, 9) [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [], [], [], []] # This filter will always return `n` rows, even if some are empty: >>> rows(range(2), 3) [[0], [1], []] """ try: n = int(n) thelist = list(thelist) except (ValueError, TypeError): return [thelist] list_len = len(thelist) split = list_len // n if list_len % n != 0: split += 1 return [thelist[split*i:split*(i+1)] for i in range(n)] def rows_distributed(thelist, n): """ Break a list into ``n`` rows, distributing columns as evenly as possible across the rows. For example:: >>> l = range(10) >>> rows_distributed(l, 2) [[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]] >>> rows_distributed(l, 3) [[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]] >>> rows_distributed(l, 4) [[0, 1, 2], [3, 4, 5], [6, 7], [8, 9]] >>> rows_distributed(l, 5) [[0, 1], [2, 3], [4, 5], [6, 7], [8, 9]] >>> rows_distributed(l, 9) [[0, 1], [2], [3], [4], [5], [6], [7], [8], [9]] # This filter will always return `n` rows, even if some are empty: >>> rows(range(2), 3) [[0], [1], []] """ try: n = int(n) thelist = list(thelist) except (ValueError, TypeError): return [thelist] list_len = len(thelist) split = list_len // n remainder = list_len % n offset = 0 rows = [] for i in range(n): if remainder: start, end = (split+1)*i, (split+1)*(i+1) else: start, end = split*i+offset, split*(i+1)+offset rows.append(thelist[start:end]) if remainder: remainder -= 1 offset += 1 return rows def columns(thelist, n): """ Break a list into ``n`` columns, filling up each column to the maximum equal length possible. For example:: >>> from pprint import pprint >>> for i in range(7, 11): ... print '%sx%s:' % (i, 3) ... pprint(columns(range(i), 3), width=20) 7x3: [[0, 3, 6], [1, 4], [2, 5]] 8x3: [[0, 3, 6], [1, 4, 7], [2, 5]] 9x3: [[0, 3, 6], [1, 4, 7], [2, 5, 8]] 10x3: [[0, 4, 8], [1, 5, 9], [2, 6], [3, 7]] # Note that this filter does not guarantee that `n` columns will be # present: >>> pprint(columns(range(4), 3), width=10) [[0, 2], [1, 3]] """ try: n = int(n) thelist = list(thelist) except (ValueError, TypeError): return [thelist] list_len = len(thelist) split = list_len // n if list_len % n != 0: split += 1 return [thelist[i::split] for i in range(split)] register.filter(rows) register.filter(rows_distributed) register.filter(columns) def _test(): import doctest doctest.testmod() if __name__ == "__main__": _test()