Skip to content

Instantly share code, notes, and snippets.

@sethrh sethrh/
Last active Sep 20, 2016

What would you like to do?
Function to simultaneously partition a list into multiple sub-lists based on used-defined criteria. Kind of like a list comprehension with multiple return values.
def multifilter(seq, *tests, multiple=False):
"""Filters items in a list into sublists corresponding to the
supplied test functions.
:returns: A list of lists of items matching conditions, in order. The last
item in the return value is the list of items that did not
match any condition.
[[items matching condition0],
[items matching condition1],
[items matching condition(N-1)],
[non-matching items]]
For example, given a list of numbers, s, you can generate a list of even
numbers and odd numbers by the following:
>>> multifilter(range(10), lambda x: x & 1)
[[1, 3, 5, 7, 9], [0, 2, 4, 6, 8]]
Also, you can do divisible by 2s and 3s like so:
>>> multifilter(range(10), lambda x: divmod(x, 2)[1] == 0,
... lambda x: divmod(x, 3)[1] == 0)
[[0, 2, 4, 6, 8], [3, 9], [1, 5, 7]]
If multiple is True, then each element will be tested against all
conditions, resulting in the possibility that the same item will exist in
multiple output arrays. In the above example, even though 6 is divisible by
3, it's not showing up in the second list. By setting multiple to True,
every test applies to each element:
>>> multifilter(range(10), lambda x: divmod(x, 2)[1] == 0,
... lambda x: divmod(x, 3)[1] == 0, multiple=True)
[[0, 2, 4, 6, 8], [0, 3, 6, 9], [1, 5, 7]]
results = [[] for i in range(len(tests))]
nonmatching = []
enumerated_tests = list(enumerate(tests)) # for efficiency
for item in seq:
found = False
for i, cond in enumerated_tests:
if cond(item):
found = True
if not multiple:
if not found:
return results
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.