[TriZPUG] iterate over a list in bunches

Josh Johnson josh_johnson at unc.edu
Wed Aug 10 21:16:00 CEST 2011


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


More information about the TriZPUG mailing list