Задать вопрос

Тел: +7 965 3737 888

533

Просмотров

8

Ответов

A couple of template filters for partitioning lists

People -- and by "people" I mean Jeff Croft -- often ask about how to split a list into multiple lists (usually for presenting as columns in a template).

These template tags provide two different ways of splitting lists -- on "vertically", and the other "horizontally".

Вопрос полезен? Да0/Нет0
file_3872.py(1.6Кб)
None

Ответы (8):

Ответtheetderks:21.05.2007
Ответ полезен? Да0/Нет0

How about this:

@register.filter
def partition_horizontal(thelist, n):
"""
Break a list into ``n`` peices, but "horizontally." That is, 
``partition_horizontal(range(10), 3)`` gives::

    [[1, 2, 3],
     [4, 5, 6],
     [7, 8, 9],
     [10]]

Clear as mud?
"""
try:
    n = int(n)
    thelist = list(thelist)
except (ValueError, TypeError):
    return [thelist]
newlists=[]
for x in range((len(thelist)-1)/n+1):
    newlists.append(thelist[x*n:x*n+n])
return newlists

Ответakaihola:10.04.2007
Ответ полезен? Да0/Нет0

Typo on line 7: "parition" > "partition"

Ответklohrenz:01.03.2007
Ответ полезен? Да0/Нет0

I modified the vertical filter so that if the list doesn't divide evenly, the last list would be the shortest (rather than longest). I thought this might be helpful to others.

I took line 44:

p = len(thelist) / n

And replaced it with this:

if (len(thelist) % n == 0):
    p = len(thelist) / n
else:
    p = (len(thelist) / n) + 1

Ответbrosner:27.02.2007
Ответ полезен? Да0/Нет0

As noted above the docstring for partition_horizontal is not what the actually implementation is generating. I have corrected the implementation to work as noted.

By the way range(10) will never give you a 10 ;)

@register.filter def partition_horizontal(thelist, n): """ Break a list into n peices, but "horizontally." That is, partition_horizontal(range(10), 3) gives::

        [[0, 1, 2],
         [3, 4, 5],
         [6, 7, 8],
         [9]]

    Clear as mud?
"""
from math import ceil
try:
    n = int(n)
    thelist = list(thelist)
except (ValueError, TypeError):
    return [thelist]
newlists = [list() for i in range(int(ceil(len(thelist) / float(n))))]
for i, val in enumerate(thelist):
    newlists[i/n].append(val)
return newlists

Eh, the highlighting didn't seem to work too well, lol.

Ответludvig.ericson:27.02.2007
Ответ полезен? Да0/Нет0

If what spencermah said is true, one could collapse this into one line:

register.filter("partition_horizontal", lambda l,n: [l[i::n] for i in range(n)])

Firstly, we have to pass a name since it is an anonymous function, secondly we pass the function with lambda style defining. Simple as pie.

Ответspencermah:27.02.2007
Ответ полезен? Да0/Нет0

partition_horizontal does not do what its docstring suggests:

>>> partition_horizontal(range(10), 3)
[[0, 3, 6, 9], [1, 4, 7], [2, 5, 8]]

Assuming the implementation is correct, a more efficient implementation uses 'extended slices' i.e. (without error-checking):

>>> def partition_horizontal_new(thelist, n):
...     return [thelist[i::n] for i in range(n)]
...     
>>> partition_horizontal_new(range(10),3)
[[0, 3, 6, 9], [1, 4, 7], [2, 5, 8]]
>>>

Ответjcroft:26.02.2007
Ответ полезен? Да0/Нет0

Err, I mean:

{% for item in sublist %}

Ответjcroft:25.02.2007
Ответ полезен? Да0/Нет0

Thanks so much for this, Jacob!

Just a small error in the docstring up top...

{% load listutil %}
{% for sublist in mylist|parition:"3" %}
    {% for item in mylist %}
        do something with {{ item }}
    {% endfor %}
{% endfor %}

I think that third line should be:

    {% for item in sublistlist %}

Right?