В итоге я выполнил большую часть этого упражнения.
Сначала найдите количество возможных мест для разделения: количество нефункциональных узлов.
def count(obj):
total = 0
for o in obj[1:]:
# Add the node itself.
total += 1
if isinstance(o, list):
total += count(o)
return total
Затем помощник: с учетом индекса в указанном выше диапазоне выясните, где он находится.
def find_idx(tree, idx):
"""
Return the node containing the idx'th function parameter, and the index of that
parameter. If the tree contains fewer than idx parameters, return (None, None).
"""
if not isinstance(idx, list):
# Stash this in a list, so recursive calls share the same value.
idx = [idx]
for i, o in enumerate(tree):
# Skip the function itself.
if i == 0:
continue
if idx[0] == 0:
return tree, i
idx[0] -= 1
if isinstance(o, list):
container, result_index = find_idx(o, idx)
if container is not None:
return container, result_index
return None, None
Теперь сделать своп довольно просто:
def random_swap(tree1, tree2):
from random import randrange
pos_in_1 = randrange(0, count(tree1))
pos_in_2 = randrange(0, count(tree2))
parent1, idx1 = find_idx(tree1, pos_in_1)
parent2, idx2 = find_idx(tree2, pos_in_2)
# Swap:
parent1[idx1], parent2[idx2] = parent2[idx2], parent1[idx1]
c = 1
tree1 = ["f:2", c, ["f:1", c]]
tree2 = ["f:2", ["f:2", ["f:2", c, c], ["f:2", c, c]], ["f:3", ["f:4", c, c, c, c], ["f:2", c, c], c]]
while True:
random_swap(tree1, tree2)
print tree1
print tree2
Это не реализует максимальную глубину, но это начало.
Это также никогда не заменит корневой узел, где узел в tree1 становится новым tree2, а все tree2 становится узлом в tree1. Обходной путь должен был бы обернуть все это в, например. [лямбда а: а, дерево], поэтому редактируемые узлы всегда имеют родительский узел.
Это не очень эффективно. Поддержание количества узлов может сделать это быстрее, но тогда вам также понадобится сохранить ссылку на родителя, чтобы эффективно обновлять счетчики. Если вы пойдете по этому пути, вы действительно захотите найти или реализовать настоящий класс дерева.