Last active
December 21, 2015 15:39
-
-
Save rik0/6328252 to your computer and use it in GitHub Desktop.
Example of function to create some classes of methods to operate on trees. Doctests are annoying, but for now they suffice. Besides, this is not as tested as it should.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def make_mr(reduce_, f, base): | |
def mr(self): | |
if not self.children: | |
return base(self) | |
else: | |
mapped = map(f, self.children) | |
red = reduce_(mapped) | |
return red | |
# return reduce_(f(child) for child in self.children) | |
return mr | |
class Node(object): | |
""" | |
>>> Node(1).height() | |
0 | |
>>> Node(1).count() | |
1 | |
>>> Node.from_array([0, 0, 0, 1, 1, 1, 2, 2, 7]).height() | |
3 | |
>>> Node.from_array([0, 0, 0, 1, 1, 1, 2, 2, 7]).count() | |
9 | |
""" | |
def __init__(self, value, *children): | |
""" | |
>>> Node(1) | |
N(1) | |
>>> Node(0, Node(1), Node(2)) | |
N(0, N(1), N(2)) | |
""" | |
self.value = value | |
self.children = list(children) | |
height = make_mr(lambda mapped_children: max(mapped_children) + 1, | |
lambda node: node.height(), | |
lambda node: 0) | |
count = make_mr(lambda mapped_children: sum(mapped_children) + 1, | |
lambda node: node.count(), | |
lambda node: 1) | |
@classmethod | |
def from_array(cls, arr): | |
""" | |
>>> Node.from_array([0]) | |
N(0) | |
>>> Node.from_array([0, 0, 0]) | |
N(0, N(1), N(2)) | |
>>> Node.from_array([0, 0, 0, 1, 1, 1, 2, 2, 7]) | |
N(0, N(1, N(3), N(4), N(5)), N(2, N(6), N(7, N(8)))) | |
>>> Node.from_array([1]) | |
Traceback (most recent call last): | |
... | |
ValueError: Invalid array spec: missing root. | |
>>> Node.from_array([0, 1]) | |
Traceback (most recent call last): | |
... | |
ValueError: Invalid array spec: multiple roots. | |
""" | |
if not arr: | |
raise ValueError("Empty container") | |
nodes = {} | |
def add(node, child): | |
new_node = cls(child) | |
nodes[child] = new_node | |
node.children.append(new_node) | |
root_index = None | |
for index, el in enumerate(arr): | |
if index == el and root_index is None: | |
root_index = index | |
nodes.setdefault(index, cls(index)) | |
elif index == el: | |
raise ValueError( | |
"Invalid array spec: multiple roots.") | |
else: | |
add(nodes.setdefault(el, cls(el)), index) | |
if root_index is not None: | |
return nodes[root_index] | |
else: | |
raise ValueError( | |
"Invalid array spec: missing root.") | |
def __str__(self): | |
if self.children: | |
return 'N(%s, %s)' % ( | |
self.value, ', '.join(str(child) for child in | |
self.children)) | |
else: | |
return 'N(%s)' % self.value | |
__repr__ = __str__ | |
if __name__ == "__main__": | |
import doctest | |
doctest.testmod() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment