Skip to content

Instantly share code, notes, and snippets.

@sethrh
Last active September 20, 2016 23:13
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save sethrh/e97d5c6b0ebc906cf267dc0ec8866a03 to your computer and use it in GitHub Desktop.
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):
results[i].append(item)
found = True
if not multiple:
break
else:
if not found:
nonmatching.append(item)
results.append(nonmatching)
return results
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment