Я работаю над задачей кода Python3, в которой сообщение кодируется или декодируется в порядке перетасовки стандартной игровой колоды из 52 карт. Я уже нашел, как закодировать сообщение, но у меня возникли трудности с обращением функции для получения сообщения в заданном порядке перетасовки. У меня есть функция, которая находит лексикографическую перестановку списка карточек на основе его индекса. Теперь мне нужен тот, который берет перестановку из списка карточек и выводит ее индекс. У меня есть некоторые идеи, но я не так хорош в теории чисел, как следовало бы. Я оставил несколько комментариев со своими идеями.
deck = ["AC", "2C", "3C", "4C", "5C", "6C", "7C", "8C", "9C", "TC", "JC", "QC", "KC",
"AD", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D", "TD", "JD", "QD", "KD",
"AH", "2H", "3H", "4H", "5H", "6H", "7H", "8H", "9H", "TH", "JH", "QH", "KH",
"AS", "2S", "3S", "4S", "5S", "6S", "7S", "8S", "9S", "TS", "JS", "QS", "KS",]
def get_nth_permutation( p_index, in_list, out_list=[] ):
if p_index >= factorial( len(in_list) ): return []
if not in_list: return out_list
f = factorial( len(in_list)-1 )
index = p_index / f # p_index * f
remainder = p_index % f # pow(p_index, -1, f) - reverse modulo?
# reverse divmod by adding index + remainder in each step to increase p_index?
out_list.append( in_list[int(index)] )
del in_list[int(index)]
if not remainder: # function should end when out_list + in_list matches deck
return out_list + in_list # return p_index
else: #keep recursion if possible
return get_nth_permutation( remainder, in_list, out_list )
Любая помощь приветствуется. Это даже не обязательно должен быть код, даже объяснение псевдокода или какие-то следующие шаги лучше, чем то, где я сейчас нахожусь.
Вы возьмете индекс первой записи и умножите его на количество возможных перестановок для остальной части списка (без этой первой записи). Повторите эту логику для следующих записей списка.
Вот реализация:
def get_permutation_index(ordered, perm):
ordered = ordered[:] # Get a copy so we don't mutate the original list
result = 0
for card in perm:
i = ordered.index(card)
ordered.pop(i)
result += i * factorial(len(ordered))
return result
Приведенная выше функция возвращает индекс, отсчитываемый от 0, точно так же, как ваша функция будет возвращать первую перестановку, когда вы передаете 0 для p_index
, и вторую, когда вы передаете 1. Если целью было начать счет с 1 (как _nth_
в вашем название функции предполагает), вам необходимо адаптировать обе функции.
Ваша функция очищает заданное in_list
. Это означает, что если вы вызовете его снова с deck
в качестве аргумента (или указанной выше функции), вы передадите пустой список. Было бы лучше, если бы ваша функция не изменяла исходный список.
Использование []
в качестве значения по умолчанию имеет побочные эффекты для последующих вызовов, в которых этот параметр опущен. См. Изменяемый аргумент по умолчанию в Python. Я бы предложил не использовать этот аргумент и вместо этого создать рекурсивный генератор, из которого вы строите список для возврата.
Не используйте оператор деления /
, а затем int()
. Вместо этого используйте оператор целочисленного деления: //
Вот ваша функция с этими адаптациями:
def get_nth_permutation( p_index, in_list): # Don't use mutable default
in_list = in_list[:] # Avoid mutating the original list
def recur(p_index):
if p_index >= factorial( len(in_list) ) or not in_list:
return
if not p_index:
yield from in_list
return
f = factorial( len(in_list)-1 )
index = p_index // f # Don't use floating point division
remainder = p_index % f
yield in_list[index]
del in_list[index]
yield from recur(remainder)
return list(recur(p_index))
Большое спасибо за ваш ответ и комментарии. Я не так хорошо знаком с Python. Я реализовал ваши адаптации, но мне неловко признаться, что я не знаю, что входит в упорядоченные и разрешенные параметры для get_permutation_index. Если колода идет по порядку, а перестановка идет в перманентном режиме, я получаю сообщение об ошибке: ValueError: 'AC' отсутствует в списке
Я добавил инструкцию в нижний фрагмент, чтобы избежать изменения исходного списка. Я думаю, вы могли запустить его перед вызовом моего кода решения (вверху), что означает, что вы передали пустой deck
.
Спасибо. Я пытался протестировать обе функции, используя get_nth_permutation в качестве входных данных для get_permutation_index, что и вызвало это. Я думаю, что ошибка может быть спорной, поскольку для каждого теста мне будет дана перестановка или сообщение, поэтому мне нужно будет использовать только ту или иную функцию, в зависимости от того, тестируется ли кодирование или декодирование. Большое спасибо за ваш отличный ответ и последующую помощь.
Подумайте, как бы вы определили порядковый номер числа по его цифрам. Например. 23 это
2 * 10**1 + 3 * 10**0