Реверсивная функция для получения лексикографического индекса данной перестановки

Я работаю над задачей кода 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 ) 

Любая помощь приветствуется. Это даже не обязательно должен быть код, даже объяснение псевдокода или какие-то следующие шаги лучше, чем то, где я сейчас нахожусь.

Подумайте, как бы вы определили порядковый номер числа по его цифрам. Например. 23 это 2 * 10**1 + 3 * 10**0

Barmar 28.07.2024 03:59
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
1
59
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы возьмете индекс первой записи и умножите его на количество возможных перестановок для остальной части списка (без этой первой записи). Повторите эту логику для следующих записей списка.

Вот реализация:

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' отсутствует в списке

ep84 28.07.2024 10:28

Я добавил инструкцию в нижний фрагмент, чтобы избежать изменения исходного списка. Я думаю, вы могли запустить его перед вызовом моего кода решения (вверху), что означает, что вы передали пустой deck.

trincot 28.07.2024 11:21

Спасибо. Я пытался протестировать обе функции, используя get_nth_permutation в качестве входных данных для get_permutation_index, что и вызвало это. Я думаю, что ошибка может быть спорной, поскольку для каждого теста мне будет дана перестановка или сообщение, поэтому мне нужно будет использовать только ту или иную функцию, в зависимости от того, тестируется ли кодирование или декодирование. Большое спасибо за ваш отличный ответ и последующую помощь.

ep84 28.07.2024 20:16

Другие вопросы по теме