Split a list into two parts based on a filter?

Chris Angelico rosuav at gmail.com
Mon Jun 10 18:50:29 EDT 2013


On Tue, Jun 11, 2013 at 6:34 AM, Roy Smith <roy at panix.com> wrote:
> new_songs = [s for s in songs if s.is_new()]
> old_songs = [s for s in songs if not s.is_new()]

Hmm. Would this serve?

old_songs = songs[:]
new_songs = [songs.remove(s) or s for s in songs if s.is_new()]

Python doesn't, AFAIK, have a "destructive remove and return"
operation, and del is a statement rather than an expression/operator,
but maybe this basic idea could be refined into something more useful.
It guarantees to call is_new only once per song.

The iterator version strikes my fancy. Maybe this isn't of use to you,
but I'm going to try my hand at making one anyway.

>>> def iterpartition(pred,it):
	"""Partition an iterable based on a predicate.

	Returns two iterables, for those with pred False and those True."""
	falses,trues=[],[]
	it=iter(it)
	def get_false():
		while True:
			if falses: yield falses.pop(0)
			else:
				while True:
					val=next(it)
					if pred(val): trues.append(val)
					else: break
				yield val
	def get_true():
		while True:
			if trues: yield trues.pop(0)
			else:
				while True:
					val=next(it)
					if not pred(val): falses.append(val)
					else: break
				yield val
	return get_false(),get_true()
>>> f,t=iterpartition(lambda x: x%3,range(100000000))
>>> next(t)
1
>>> next(t)
2
>>> next(t)
4
>>> next(t)
5
>>> next(f)
0
>>> next(f)
3
>>> next(f)
6
>>> next(f)
9
>>> next(f)
12
>>> next(t)
7
>>> next(t)
8

Ha. :) Useless but fun.

ChrisA



More information about the Python-list mailing list