简单的行转置密码

发布于 2024-10-08 16:01:30 字数 975 浏览 3 评论 0原文

对于 Lisp 课程,我们被布置了一个简单的行转置密码作业,我也尝试在 Haskell 中解决该作业。基本上,只需将字符串拆分为长度为 n 的行,然后转置结果。所得到的字符列表的串联就是加密的字符串。解码有点困难,因为输入的最后一行中可能缺少元素(结果中的不完整列),必须注意这一点。

这是我在 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

它可以完成工作,但我不确定这是否被认为是惯用的 Haskell,因为我对索引的摆弄并没有感觉太声明性。这是否可以改进?如果可以,如何改进?

顺便问一下:Haskell 98 中有类似 insertAt 的东西吗?即,将给定索引处的元素或列表插入到列表中的函数。

注意:这不是作业的一部分,无论如何,作业都是今天到期的。

For a Lisp class, we were given a simple row transposition cipher homework, which I tried to solve in Haskell, too. Basically, one just splits a string into rows of length n, and then transposes the result. The concatenation of the resulting list of lists of chars is the encrypted string. Decoding is a little harder, since there may be missing elements in the last row of input (incomplete columns in the result), which have to be taken care of.

This is my solution 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

It does the job, but I am not sure, whether this would be considered idiomatic Haskell, since my fiddling with the indices does not feel too declarative. Could this be improved, and if yes, how?

By the way: Is there something akin to insertAt in Haskell 98? I.e. a function inserting an element or list at a given index into a list.

Note: This is NOT part of the homework, which was due today anyway.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

留蓝 2024-10-15 16:01:30

我会通过稍微不同地查看encodedecode 问题来做到这一点。 encode 将数据分解为 n 列矩阵,然后将其转置(转置为 n 行矩阵)并按行连接。 decode 将数据分解为 n 行矩阵,然后将其转置(转换为 n 列矩阵)并按行连接。

因此,我首先定义两个函数 - 一个将数组制作为 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

另一个将数组切片为 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

现在,编码解码相当简单:

encode :: Int -> [a] -> [a]
encode = ((concat . transpose) .). chunk
decode :: Int -> [a] -> [a]
decode = ((concat . transpose) .). slice

I would do this by looking at the encode and decode problems slightly differently. encode breaks up the data into a n-column matrix, which it then transposes (into a n-row matrix) and concatenates by rows. decode breaks up the data into a n row matrix, which it then transposes (into a n columm matrix) and concatenates by rows.

So I'd start by defining two functions - one to make an array into an n column matrix:

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

and another to slice an array into an n row matrix:

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

Now, encoding and decoding is fairly easy:

encode :: Int -> [a] -> [a]
encode = ((concat . transpose) .). chunk
decode :: Int -> [a] -> [a]
decode = ((concat . transpose) .). slice
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文