Hierarchical data from the closure property
When your data has 'parts of parts', a single list level is not enough.
x = [[1, 2], 3, 4]
print(x)
# Closure: we can put the whole structure inside another list
xx = [x, x]
print(xx)
def tree(node_label, branches=None):
if branches is None:
branches = []
# A tree is a list: [label, branch1, branch2, ...]
return [node_label] + list(branches)def label(t):
return t[0]def branches(t):
return t[1:]def is_leaf(t):
return len(branches(t)) == 0tree(label, branches)label(t), branches(t), is_leaf(t)def count_leaves(t):
if is_leaf(t):
return 1
return sum(count_leaves(b) for b in branches(t))
print(count_leaves(t))
count_leaves(t)def tree_map(f, t):
return tree(
f(label(t)),
[tree_map(f, b) for b in branches(t)]
)
squared = tree_map(lambda x: x * x, t)
plus_one = tree_map(lambda x: x + 1, t)
print(label(plus_one))
print(squared)
print(plus_one)
tree_map(lambda x: x + 1, t)$$ F(t)\;=\;\text{combine}\Big(\text{label}(t),\;[\,F(b)\;\text{for}\;b\in\text{branches}(t)\,]\Big) $$
def find_path(t, target):
"""Return a list of labels from the root to target, or None."""
if label(t) == target:
return [label(t)]
for b in branches(t):
subpath = find_path(b, target)
if subpath is not None:
return [label(t)] + subpath
return None
# Predict before you run:
# What do you think find_path(t, 2) returns?
print(find_path(t, 2))
# What do you think find_path(t, 1) returns?
print(find_path(t, 1))
# And what about a missing label?
print(find_path(t, 99))
def fib_tree(n):
if n <= 1:
return tree(n)
left = fib_tree(n - 1)
right = fib_tree(n - 2)
return tree(label(left) + label(right), [left, right])
ft5 = fib_tree(5)
print(label(ft5))
print(count_leaves(ft5))
# Reminder setup for this exit ticket:
# t = ... (the same tree used earlier in the lesson)
# def find_path(t, target): ...
print(find_path(t, 1))
find_path(t, 1)
Powered by SciMigo AI Tutor - https://scimigo.com