Inspired by @gnibbler's great (but terse!) answer, we can apply that approach to map to multiple partitions:
from collections import defaultdictdef splitter(l, mapper):"""Split an iterable into multiple partitions generated by a callable mapper.""" results = defaultdict(list) for x in l: results[mapper(x)] += [x] return results
Then splitter
can then be used as follows:
>>> l = [1, 2, 3, 4, 2, 3, 4, 5, 6, 4, 3, 2, 3]>>> split = splitter(l, lambda x: x % 2 == 0) # partition l into odds and evens>>> split.items()>>> [(False, [1, 3, 3, 5, 3, 3]), (True, [2, 4, 2, 4, 6, 4, 2])]
This works for more than two partitions with a more complicated mapping (and on iterators, too):
>>> import math>>> l = xrange(1, 23)>>> split = splitter(l, lambda x: int(math.log10(x) * 5))>>> split.items()[(0, [1]), (1, [2]), (2, [3]), (3, [4, 5, 6]), (4, [7, 8, 9]), (5, [10, 11, 12, 13, 14, 15]), (6, [16, 17, 18, 19, 20, 21, 22])]
Or using a dictionary to map:
>>> map = {'A': 1, 'X': 2, 'B': 3, 'Y': 1, 'C': 2, 'Z': 3}>>> l = ['A', 'B', 'C', 'C', 'X', 'Y', 'Z', 'A', 'Z']>>> split = splitter(l, map.get)>>> split.items()(1, ['A', 'Y', 'A']), (2, ['C', 'C', 'X']), (3, ['B', 'Z', 'Z'])]