0

I have a list of objects from which I have filtered out those that have a particular value in a single attribute:

import itertools 
iterator = itertools.ifilter(lambda record: record.outcome==1, list) 

The iterator has now all objects with outcome = 1

However, they now differ in the value of another attribute order=X

I would like to partition the iterator in two: one for those objects whose order = 1

and another one for those with order > 1

Is there a another way than looping over all elements and adding them to one of the two lists / a list comprehension?

Say I have a list l with obj1,obj2,obj3 as content where obj1.order=1, obj2.order=2 and obj3.order=3 I would like to yield a # containing obj1 and b # containing obj2 & obj3

Preferably, I would like to have two other iterators so that I can do with the partial lists whatever I would like to do!

I was thinking about itertools.groupby but as my variable order=X has a number of possible values, it would give me more than two sub-iterators!

  • Welcome to SO! Please us the [edit link](https://stackoverflow.com/posts/37293084/edit) on your question to show sample list with the expected output. – styvane May 18 '16 at 07:42
  • Possible duplicate of [Python: split a list based on a condition?](http://stackoverflow.com/questions/949098/python-split-a-list-based-on-a-condition) – user2390182 May 18 '16 at 07:53
  • 1
    You probably want `itertools.tee`. That will duplicate your current iterator and then you can filter one on `order == 1` and one on `order > 1`. – Alex Hall May 18 '16 at 08:01
  • Not really a duplicate, that deals with lists, this deals with generators and doesn't really want to create separate lists. – Brendan Abel May 18 '16 at 08:02
  • Why not just use a for loop? Your lambdas are going to completely hammer the performance of ifilter so there is no advantage at all, tee is also goint to probably more expensive than just calling list so again no advantage. – Padraic Cunningham May 18 '16 at 08:25

1 Answers1

0

Use tee and ifilter. You don't absolutely need the tee, but it potentially makes it more efficient if the original iterator is expensive.

import itertools 
iter_outcome = itertools.ifilter(lambda record: record.outcome==1, list)
a, b = itertools.tee(iter_outcome, 2)
iter_order_1 = itertools.ifilter(lambda record: record.order == 1, a)
iter_greater_1 = itertools.ifilter(lambda record: record.order > 1, b)
Brendan Abel
  • 35,343
  • 14
  • 88
  • 118
  • thx! What do you mean by 'expensive' => exhausive i.e. that it does not provide a possibly infinite number of objects? – Andrew Tobey May 18 '16 at 08:14
  • If you use `tee`, it only has to do the `outcome==1` filter once for each element in the original iterator, without the `tee`, it ends up doing it twice for each element in the original iterator -- once for *each* of the secondary iterators. – Brendan Abel May 18 '16 at 08:33