Skip to content

Commit 49f381e

Browse files
kurtbrosemahmoud
authored andcommitted
Extend partition to accept multiple predicates
1 parent 1737473 commit 49f381e

2 files changed

Lines changed: 57 additions & 5 deletions

File tree

boltons/iterutils.py

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -754,10 +754,15 @@ def value_transform(x): return f(x[1])
754754
return ret
755755

756756

757-
def partition(src, key=bool):
757+
def partition(src, key=bool, *keys):
758758
"""No relation to :meth:`str.partition`, ``partition`` is like
759-
:func:`bucketize`, but for added convenience returns a tuple of
760-
``(truthy_values, falsy_values)``.
759+
:func:`bucketize`, but for added convenience returns a collection for
760+
each predicate passed.
761+
762+
``partition`` now accepts multiple *key* functions and will return
763+
``N + 1`` lists for ``N`` predicates. Each value from *src* is placed
764+
into the first list whose predicate evaluates to ``True`` with values
765+
that match none of the predicates placed in the last list.
761766
762767
>>> nonempty, empty = partition(['', '', 'hi', '', 'bye'])
763768
>>> nonempty
@@ -772,9 +777,37 @@ def partition(src, key=bool):
772777
>>> decimal_digits, hexletters = partition(string.hexdigits, is_digit)
773778
>>> ''.join(decimal_digits), ''.join(hexletters)
774779
('0123456789', 'abcdefABCDEF')
780+
781+
Multiple predicates may be supplied to divide into more buckets:
782+
783+
>>> positive, negative, zero = partition(range(-1, 2),
784+
... lambda i: i > 0,
785+
... lambda i: i < 0)
786+
>>> positive, negative, zero
787+
([1], [-1], [0])
775788
"""
776-
bucketized = bucketize(src, key)
777-
return bucketized.get(True, []), bucketized.get(False, [])
789+
if not is_iterable(src):
790+
raise TypeError('expected an iterable')
791+
792+
def _make_key_func(k):
793+
if isinstance(k, str):
794+
return lambda x, k=k: getattr(x, k, False)
795+
if callable(k):
796+
return k
797+
raise TypeError('expected key to be callable or a string')
798+
799+
key_funcs = [_make_key_func(key)] + [_make_key_func(k) for k in keys]
800+
parts = [[] for _ in range(len(key_funcs) + 1)]
801+
802+
for val in src:
803+
for idx, func in enumerate(key_funcs):
804+
if func(val):
805+
parts[idx].append(val)
806+
break
807+
else:
808+
parts[-1].append(val)
809+
810+
return tuple(parts)
778811

779812

780813
def unique(src, key=None):

tests/test_iterutils.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,3 +616,22 @@ def test_windowed_filled():
616616

617617
assert list(windowed_iter(range(4), 3)) == [(0, 1, 2), (1, 2, 3)]
618618
assert list(windowed_iter(range(4), 3, fill=None)) == [(0, 1, 2), (1, 2, 3), (2, 3, None), (3, None, None)]
619+
# Tests for partition
620+
621+
def test_partition_default():
622+
from boltons.iterutils import partition
623+
624+
nonempty, empty = partition(['', '', 'hi', '', 'bye'])
625+
assert nonempty == ['hi', 'bye']
626+
assert empty == ["", "", ""]
627+
628+
629+
def test_partition_multiple():
630+
from boltons.iterutils import partition
631+
632+
items = [2, -1, 0, 3, -2]
633+
positive, negative, zero = partition(items, lambda i: i > 0, lambda i: i < 0)
634+
assert positive == [2, 3]
635+
assert negative == [-1, -2]
636+
assert zero == [0]
637+

0 commit comments

Comments
 (0)