Semplice fila cifrario a trasposizione
-
11-10-2019 - |
Domanda
Per una classe Lisp, ci hanno dato un sistema di cifratura compiti fila trasposizione, che ho cercato di risolvere in Haskell, anche. Fondamentalmente, uno solo divide una stringa in file di lunghezza n
, e poi traspone il risultato. La concatenazione della lista risultante di liste di caratteri è la stringa crittografata. Decodifica è un po 'più difficile, in quanto vi possono essere elementi dell'ultima fila di ingresso (colonne incomplete del risultato), che devono essere curati mancanti.
Questa è la mia soluzione in Haskell:
import Data.List
import Data.Ratio
import Data.List.Split
encode :: String -> Int -> String
encode s n = concat . transpose $ chunk n s
decode :: String -> Int -> String
decode s n = take len $ encode s' rows
where s' = foldr (insertAt " ") s idxs
rows = ceiling (len % n)
idxs = take (n-filled) [n*rows-1,(n-1)*rows-1..]
filled = len - n * (rows - 1)
len = length s
insertAt :: [a] -> Int -> [a] -> [a]
insertAt xs i ys = pre ++ xs ++ post
where (pre,post) = splitAt i ys
Si fa il lavoro, ma non sono sicuro, se questo sarebbe considerato idiomatica Haskell, dato che la mia giocherellare con gli indici non si sente troppo dichiarativo. Questo potrebbe essere migliorato, e se sì, come?
A proposito: C'è qualcosa di simile ad insertAt
in Haskell 98? Cioè una funzione inserimento di un elemento o un elenco in un determinato indice in una lista.
Nota. Questo non fa parte del lavoro, che era in scadenza oggi comunque
Soluzione
Vorrei farlo guardando i problemi encode
e decode
in modo leggermente diverso. interruzioni encode
up i dati in una matrice n
colonne, che poi traspone (in una matrice n
riga) e concatena per righe. interruzioni decode
up i dati nel una matrice fila n
, che poi traspone (in una matrice n
columm) e concatena per righe.
Così mi piacerebbe iniziare con la definizione di due funzioni - uno a fare una matrice in una matrice colonna n
:
chunk:: Int -> [a] -> [[a]]
chunk n as = chunk' n (length as) as
where chunk' n l as | l <= n = [as]
| otherwise = some : chunk' n (l-n) rest
where (some, rest) = splitAt n as
ed un altro per tagliare una matrice in una matrice riga n
:
slice :: Int -> [a] -> [[a]]
slice n as = chunk (q+1) front ++ chunk q back
where (q,r) = length as `divMod` n
(front, back) = splitAt (r*(q+1)) as
Ora, codifica e decodifica è abbastanza facile:
encode :: Int -> [a] -> [a]
encode = ((concat . transpose) .). chunk
decode :: Int -> [a] -> [a]
decode = ((concat . transpose) .). slice