isinstance()
+ itertools.permutations()
- хорошее направление, просто вам нужен их продукт, и некоторое отслеживание, какая перестановка применима к какой части дерева (?) (Я размышлял над генерацией всех возможных обходовдерево):
import itertools
def plan(part,res):
if isinstance(part,list) and len(part)>1:
res.append(itertools.permutations(range(len(part))))
for elem in part:
plan(elem,res)
return res
def remix(part,p):
if isinstance(part,list) and len(part)>1:
coll=[0]*len(part)
for i in range(len(part)-1,-1,-1):
coll[i]=remix(part[i],p)
mix=p.pop()
return [coll[i] for i in mix]
else:
return part
def swap(t):
plans=itertools.product(*plan(t,[]))
for p in plans:
yield remix(t,list(p))
for r in swap([['a', 'b', 'c'], ['d'], ['e', 'f', ['g', ['h', 'i']]]]):
print(r)
plan()
рекурсивно находит все "реальные" списки (которые имеют более одного элемента) и создает для них itertools.permutations()
.
swap()
звонки plan()
, а затем объединяет перестановки в одну составную мегапермутацию с помощью itertools.product()
remix()
создает фактический объект для одного шага мегапермутации. Это немного сложно, потому что я не хотел бороться с отслеживанием древовидной позиции, вместо этого remix()
работает в обратном направлении, переходя к самому последнему списку и добавляя его к самому последнему компоненту текущего плана, удаляя его из списка. .
Кажется, что это работает, хотя ваш пример немного длинный, с более простыми входами он имеет управляемый вывод:
for r in swap([['a', ['b', 'c']], ['d'], 'e']):
print(r)
[['a', ['b', 'c']], ['d'], 'e']
[['a', ['c', 'b']], ['d'], 'e']
[[['b', 'c'], 'a'], ['d'], 'e']
[[['c', 'b'], 'a'], ['d'], 'e']
[['a', ['b', 'c']], 'e', ['d']]
[['a', ['c', 'b']], 'e', ['d']]
[[['b', 'c'], 'a'], 'e', ['d']]
[[['c', 'b'], 'a'], 'e', ['d']]
[['d'], ['a', ['b', 'c']], 'e']
[['d'], ['a', ['c', 'b']], 'e']
[['d'], [['b', 'c'], 'a'], 'e']
[['d'], [['c', 'b'], 'a'], 'e']
[['d'], 'e', ['a', ['b', 'c']]]
[['d'], 'e', ['a', ['c', 'b']]]
[['d'], 'e', [['b', 'c'], 'a']]
[['d'], 'e', [['c', 'b'], 'a']]
['e', ['a', ['b', 'c']], ['d']]
['e', ['a', ['c', 'b']], ['d']]
['e', [['b', 'c'], 'a'], ['d']]
['e', [['c', 'b'], 'a'], ['d']]
['e', ['d'], ['a', ['b', 'c']]]
['e', ['d'], ['a', ['c', 'b']]]
['e', ['d'], [['b', 'c'], 'a']]
['e', ['d'], [['c', 'b'], 'a']]
24 перестановок, как и ожидалось