Страницы

Поиск по вопросам

понедельник, 24 февраля 2020 г.

Поворот матрицы на 90, 180, 270 градусов. Шифровальная решетка

#python #инспекция_кода


Друзья, задача следующая : Дана шифровальная решетка и зашифрованный пароль, как
список (list) строк. Пример:

('X...',
 '..X.',
 'X..X',
 '....'),

('itdf',
 'gdce',
 'aton',
 'qrdi'))


Необходимо "накладывая" первый список на второй получать значения со второго списка,если
символу в одном списке соответствует символ "Х" в другом списке. Далее поворачиваем
матрицу с символами "Х" и проводим операцию повторно. 90, 180, 270. Полученные значения
со второго списка - на вывод.

Решение к данной задаче я написал, прошу Вас посмотреть, и сделать замечания по написанному
мною коду. 

def recall_password(cipher_grille, ciphered_password):
    list = ""                                                          #Список, где
будут храниться полученные данные
    turn = 0                                                           #Счетчик
    while turn < 4:
        for elem1, elem2 in zip(ciphered_password, cipher_grille):     #Заходим в
каждый из списков
            for word1, word2 in zip(elem1, elem2):                     #Получаем
значения из каждого списка
                if word2 == "X":
                    list += word1
        cipher_grille = tuple(zip(*cipher_grille[::-1]))               #Поворачиваем
матрицу на 90 градусов"
        turn += 1
    print(list)
    return list


Моё решение по поводу цикла while и счетчика кажется некрасивым, надеюсь, Вы сможете
подсказать, как можно сделать код "симпотичнее".
Спасибо
    


Ответы

Ответ 1



Когда нужно выполнить последовательность действий заданное число раз, обычно используют такую конструкцию: for _ in range(number_of_times): # some code И ещё - у вас на самом глубоком уровне вложенности код имеет пять отступов (первый уровень вы, кстати, потеряли при копировании кода). Это много. Когда потом ваш код будет читать другой программист (или вы сами через несколько недель), то будет сложно разбираться в этих нагромождениях. Если замечаете, что код у вас начинает громоздится в такие монструозные конструкции, то посмотрите - нельзя ли вынести что-то в отдельные небольшие функции. Сам я решил эту задачу таким образом: from itertools import compress def recall_password(cipher_grille, ciphered_password): letters = ''.join(ciphered_password) def turn(matrix): return list(''.join(tpl) for tpl in zip(*matrix[::-1])) def gain(template, letters): t = ''.join(template) t = [(lambda i: 1 if i == 'X' else 0)(i) for i in t] return ''.join(compress(letters, t)) res = [] for _ in range(4): res.append(gain(cipher_grille, letters)) cipher_grille = turn(cipher_grille) return ''.join(res) Кстати, если у вас ещё будут вопросы по поводу заданий с checkio, то указывайте, как эта задача называется на сайте и из какого она раздела. А то точно помню, что делал эту задачу, но нашёл её далеко не сразу.

Ответ 2



"Креативное" векторизированное решение на Numpy + Pandas (почти без циклов): import numpy as np import pandas as pd data = ( ('X...', '..X.', 'X..X', '....'), ('itdf', 'gdce', 'aton', 'qrdi')) df = pd.DataFrame(list(data), index=['grid','code']).T grid_arr = df.grid.str.extractall(r'(.)').unstack().eq('X').values data_arr = df.code.str.extractall(r'(.)').unstack().values result = ''.join([''.join(data_arr[np.rot90(grid_arr, -i)].tolist()) for i in range(4)]) Результат: icantforgetiddqd Некоторые пояснения: In [58]: df Out[58]: grid code 0 X... itdf 1 ..X. gdce 2 X..X aton 3 .... qrdi In [59]: grid_arr Out[59]: array([[ True, False, False, False], [False, False, True, False], [ True, False, False, True], [False, False, False, False]], dtype=bool) In [60]: data_arr Out[60]: array([['i', 't', 'd', 'f'], ['g', 'd', 'c', 'e'], ['a', 't', 'o', 'n'], ['q', 'r', 'd', 'i']], dtype=object) In [61]: data_arr[grid_arr] Out[61]: array(['i', 'c', 'a', 'n'], dtype=object)

Ответ 3



Я бы сделал так. Приводим к плоскому массиву и фильтруем. def compress(key, val): # similar for itertools.compress key = list(''.join(key)) # make all in one list like ['........'] val = list(''.join(val)) return ''.join(v for v, k in zip(val, key) if k=='X') С помощью zip поворачиваем массив. Полученные строки необходимо еще развернуть. def right_rotate(array): return tuple(map(lambda a: ''.join(reversed(a)),zip(*array))) Вычисляем if __name__ == '__main__': key = ( 'X...', '..X.', 'X..X', '....') value = ('itdf', 'gdce', 'aton', 'qrdi') (k,v) = (key, value) l = '' for i in range(0,4): l +=compress(k,v) k = right_rotate(k) print(l)

Комментариев нет:

Отправить комментарий