Я столкнулся с проблемой, когда хочу написать простой код перестановки,
def permutation(Ori, Curr, used):
if len(Ori) == len(Curr):
#print Curr
return
for i in xrange(len(Ori)):
if used[i]:
continue
used[i] = True
Curr.append(Ori[i])
print Curr,i," after append"
permutation(Ori, Curr, used) # further level
used[i] = False
print Curr,i," before delete"
Curr = Curr[0:-1] # Curr.pop() works
print Curr,i," after delete"
return
if __name__ == "__main__":
used = [False]*3
Curr = []
permutation([1,2,3], Curr, used)
в то время как результат неверен:
[1] 0 after append
[1, 2] 1 after append
[1, 2, 3] 2 after append
[1, 2, 3] 2 before delete
[1, 2] 2 after delete <------
[1, 2, 3] 1 before delete <------
[1, 2] 1 after delete
[1, 2, 3] 2 after append
[1, 2, 3] 2 before delete
[1, 2] 2 after delete
[1, 2, 3] 0 before delete
[1, 2] 0 after delete
[1, 2, 2] 1 after append
[1, 2, 2] 1 before delete
[1, 2] 1 after delete
[1, 2, 3] 2 after append
[1, 2, 3] 2 before delete
[1, 2] 2 after delete
Я не знаю, почему у массива есть дополнительный номер на указанном шаге.
Извините, возможно, я не задал свой вопрос, я просто хочу знать причину, почему эта рекурсия вернула список, который, как я предполагал, был сжат. Я написал еще один фрагмент кода, может ли кто-нибудь сказать мне разницу между двумя комментариями? (A = A [0: -1] и A.pop())
def f(A):
if(len(A) == 10):
return
A.append('a')
f(A)
print A
# A = A[0:-1]
# A.pop()
return
if __name__ == "__main__":
f([])
В строке
permutation(Ori, Curr, used) # further level
вы указываете указатели на списки, а не на копии списков. Выполняя это, когда permutation
изменяет Curr
, вы видите изменения в вызывающем контексте. Одним из возможных решений является вызов
permutation(Ori, Curr[:], used) # further level
который передает копию Curr.
Потому что он изменяет Curr
. Он действительно удаляет элемент из Curr
до возвращения функции.
Использование Curr = Curr[0:-1]
создает копию Curr
без одного элемента. Элемент не удаляется из исходного списка (к которому у вызывающего контекста еще есть доступ). Поэтому практически ничего не происходит, потому что новый список без последнего элемента забывается, как только возвращается функция.
Другим возможным решением было бы не изменять полученный Curr
вообще - заменить
Curr.append(Ori[i])
с
Curr = Curr + [Ori[i]]
Существует уже функция для создания перестановок:
http://docs.python.org/library/itertools.html#itertools.permutations
Примерный код (определенный в терминах product
) - это "обычная" реализация на основе generator- по моему скромному мнению.
В случае, когда полезно подумать, вот код для генерации всех перестановок итерации:
def permutations(iter):
"""
>>> print(list( permutations(range(3)) ))
[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]
"""
elements = list(iter)
# base case
if len(elements)==0:
yield []
for i,elem in enumerate(elements):
withoutElem = elements[:i]+elements[i+1:]
for perm in permutations(withoutElem):
yield [elem]+perm