Skip to content

Instantly share code, notes, and snippets.

@Per48edjes
Created October 31, 2022 22:36
Show Gist options
  • Save Per48edjes/a32f3c11ad8e4467fb47e6495c3c4025 to your computer and use it in GitHub Desktop.
Save Per48edjes/a32f3c11ad8e4467fb47e6495c3c4025 to your computer and use it in GitHub Desktop.
Using generators, recursion, and decorators to return all even subsets of a sequence
#!/usr/bin/env python3
"""
Problem inspired by "Even Subsets" found here:
https://cs61a.org/assets/slides/28-Scheme_Lists_full.pdf
Playing around with recursion, generators, and decorators...of course, this
is completely for my own edification. I would not recommend writing code like
this in an applied setting... :)
"""
from typing import Iterable, Generator, List, Callable
def is_even(g: Generator[List, None, None]) -> Callable:
def wrapper(*args):
for subset in g(*args):
if sum(subset) % 2 == 0:
yield subset
return wrapper
@is_even
def subset_gen(s: Iterable[int]) -> Generator[List[int], None, None]:
"""
Generator that returns non-empty subsets of iterable `s` as lists, recursively
>>> t0 = all_subsets([])
>>> next(t0)
Traceback (most recent call last):
StopIteration
>>> t1 = all_subsets((1,))
>>> for e in t1:
... print(e)
[1]
>>> t2 = all_subsets((1, 2))
>>> for e in t2:
... print(e)
[1]
[1, 2]
[2]
>>> t2 = all_subsets([k+1 for k in range(3)])
>>> for e in t2:
... print(e)
[1]
[1, 2]
[2]
[1, 2, 3]
[2, 3]
[1, 3]
[3]
"""
# Encapsulate the recursion otherwise any decorator is applied to recursive
# calls, too, since the look up finds function name in global frame, wherein
# it's being decorated!
#
# See the following issue for more info:
# https://stackoverflow.com/questions/13915122/how-to-decorate-a-generator-in-python
def gen(s: Iterable[int]) -> Generator[List[int], None, None]:
if s:
first, rest = list(s[:1]), list(s[1:])
yield first
for subset in gen(rest):
yield first + subset
yield subset
return gen(s)
def main():
s = [3, 4, 5, 7] # Test case for decorated generator
for even_subset in subset_gen(s):
print(even_subset)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment