[Tutor] __iter__ loops, partitioning list among children

Eric Abrahamsen eric at ericabrahamsen.net
Mon Aug 25 05:49:10 CEST 2008


On Aug 24, 2008, at 7:20 PM, Kent Johnson wrote:

> Forwarding to the list with my reply. Please use Reply All to reply  
> to the list.

Grr, sorry, I keep forgetting...

>
>
> On Sun, Aug 24, 2008 at 1:02 AM, Eric Abrahamsen
> <eric at ericabrahamsen.net> wrote:
>>
>> On Aug 23, 2008, at 11:22 PM, Kent Johnson wrote:
>>
>>> On Sat, Aug 23, 2008 at 6:47 AM, Eric Abrahamsen
>>> <eric at ericabrahamsen.net> wrote:
>>>>
>>>> At first I thought the bisect module was the way to go, but it is  
>>>> too
>>>> tightly tied to integer list indices, and works very awkwardly when
>>>> bisecting on datetime attributes.
>>>
>>> I'm not sure what the problem is with bisect (to find the starting
>>> point). Your list of model elements has integer indices. I think you
>>> have to write a __cmp__ method for your model class that compares on
>>> the datetime attribute, then it should work. You can also create a
>>> list of (key, model) and sort/search that.
>>> http://www.mail-archive.com/python-list@python.org/msg189443.html
>>
>> The __cmp__ trick is very nice, and would do it, except I won't  
>> have access
>> to the events model classes. I could get bisect to work by feeding  
>> it a list
>> comprehension, but making the high and low parameters work required  
>> integer
>> indices, which seemed like one half-hack too many...
>
> I don't understand the issue. *All* lists have integer indices. If you
> make a list of (key, model) pairs, the keys only need to be
> comparable, not integers.

The main problem is that I don't have any control over the list of  
models, and all I've got is the name of a datetime attribute to filter  
by. The only way I could get bisect to work was like this:

index = bisect([getattr(x, attr_name) for x in model_list],  
sentinel_date)

But that loops over the whole list, which is what I was trying to  
avoid. And the only way I could provide high and low parameters to  
bisect is by calling event_list.index(event), which doesn't work on  
django querysets. I also experimented with itertools.groupby to  
produce groups of events, but that turned out to be far slower than  
simply looping over the whole event list and extracting events which  
test true for c.start <= getattr(event, attr_name) < c.stop.

Ideally I could create a kind of concurrent iterator, that steps  
through children's blocks of time and the object's event list in  
tandem, rather than going over the whole events list once for every  
child produced. Maybe that's not possible... I'm pasting the whole  
function down below, just for the hell of it.

Thanks again,
Eric


def _iter_children(self, child, require_events=False):
         """
         Iterate through an object's 'child' items.

         If require_events == True, only return children with
         events, otherwise return all children.
         """
         while self.sentinel < self.stop:
             c = child([], self.sentinel, self.start_attr,  
rolling=self.rolling, counts_only=self.counts_only)
             for e in self.events:
                 if c.start <= getattr(e,self.start_attr) < c.stop:
                     c.events.append(e)
             self.sentinel += c.dt_range
             if not require_events or c.has_events():
                 yield c


More information about the Tutor mailing list