[TriZPUG] iterate over a list in bunches

Kurt Grandis KGrandis at lexile.com
Thu Aug 11 14:51:51 CEST 2011


If you prefer the itertools route you can make use of a pattern described on the itertools doc page called 'grouper'.

import itertools

class GroupIter(object):
     def __init__(self, data, group_size=4, fill=None):
        self._data = data
        self._group_size = group_size
        self._fill = fill

     def __iter__(self):
         #checkout itertools for related functions
         groups = itertools.izip_longest(fillvalue=self._fill,
                                      *[iter(self._data)]*self._group_size)
         for group in groups:
             # if you prefer truncation to fill, uncomment next line
             group = [g for g in group if g is not None]
             yield group


data = range(1, 34)
obj = GroupIter(data, 4)
print "data: %s, count: %s" % (data, len(data))
for ix,row in enumerate(obj):
     print "Row: #%d" % (ix)
     for field in row:
        print "%s " % (field,),
     print "\n---------------------------"


-----Original Message-----
From: trizpug-bounces+kgrandis=lexile.com at python.org [mailto:trizpug-bounces+kgrandis=lexile.com at python.org] On Behalf Of Josh Johnson
Sent: Wednesday, August 10, 2011 3:16 PM
To: trizpug at python.org
Subject: Re: [TriZPUG] iterate over a list in bunches

Some updates (thanks bac!):

import math

class testiter(object):
     _row = 0
     _rowcount = 4
     _data = range(1, 34)
     _counter = 0

     @property
     def rows(self):
         return int(math.ceil(len(self._data)/float(self._rowcount)))

     @property
     def row(self):
         return self._counter/self._rowcount

     def __iter__(self):
         """
         Returns one row of fields at a time
         """
         start = self._counter
         end = start+self._rowcount

         row = self._data[start:end]

         self._counter = end

         for field in row:
             yield field

         if len(row) < self._rowcount:
             raise StopIteration


obj = testiter()
print "data: %s, count: %s, rows: %s" % (obj._data, len(obj._data), 
obj.rows)
for x in range(0, obj.rows+1):
     print "Row: #%s" % (obj.row)
     for field in obj:
         print "%s " % (field,),
     print "\n---------------------------"

Now it keeps track of the row number with some math, and avoids 
unnecessarily performing multiplication when addition will suffice. I've 
also added a StopIteration exception when we're on the last row, I'm not 
sure if that's actually doing anything useful.

JJ

On 8/10/2011 12:40 PM, Josh Johnson wrote:
> Hi all,
> I had a use case where I had to iterate over a linear list of objects 
> in bunches, for display in a tabular layout[1], this is how I 
> implemented it, I'm interested in feedback on the approach:
>
> import math
>
> class testiter(object):
>     _row = 0
>     _rowcount = 4
>     _data = range(1, 34)
>
>     @property
>     def rows(self):
>         return int(math.ceil(len(self._data)/float(self._rowcount)))
>
>     def __iter__(self):
>         """
>         Returns one row of fields at a time
>         """
>         start = self._row*self._rowcount
>         end = start+self._rowcount
>
>         row = self._data[start:end]
>
>         self._row += 1
>         for field in row:
>             yield field
>
>
>
> obj = testiter()
> print "data: %s, count: %s, rows: %s" % (obj._data, len(obj._data), 
> obj.rows)
> for x in range(0, obj.rows+1):
>     for field in obj:
>         print "%s " % (field,),
>     print "\n---------------------------"
>
> Running this through python (tested with 2.6.6), yields this output 
> (the dump of the data in the first line truncated a bit for brevity):
>
> data: [1, ... 33], count: 33, rows: 9
> 1  2  3  4
> ---------------------------
> 5  6  7  8
> ---------------------------
> 9  10  11  12
> ---------------------------
> 13  14  15  16
> ---------------------------
> 17  18  19  20
> ---------------------------
> 21  22  23  24
> ---------------------------
> 25  26  27  28
> ---------------------------
> 29  30  31  32
> ---------------------------
> 33
> ---------------------------
>
> ---------------------------
>
> Critiques?
>
> Thanks,
> JJ
>
> [1] For the record, it was displaying a list of dyanically-generated 
> form fields from a Django ModelForm in a template. I was able to just 
> call {% for field in form %} multiple times for each row.
>


-- 
Josh Johnson
Applications Analyst
Translational Pathology Laboratory
Lineberger Comprehensive Cancer Center
University of North Carolina at Chapel Hill
(919) 923-0894
_______________________________________________
TriZPUG mailing list
TriZPUG at python.org
http://mail.python.org/mailman/listinfo/trizpug
http://trizpug.org is the Triangle Zope and Python Users Group


More information about the TriZPUG mailing list