通过重新排列Haskell中的列表进行编码和解码
问题描述:
我正在尝试编写两个单独的程序,可用于编码,然后解码单词或短语。编码需要检查消息的长度(包括空格)是否为2复合数字。也就是说,它恰好有两个因素,不包括1和本身。如果它不是2复合,则必须添加'X'直到它是2复合。然后,通过将消息排列在具有其因素的维度的网格中,并将其读取而不是跨过,来完成实际的编码。所以“我在这里挣扎”这个词有20个字符,需要变成“我在这里挣扎X”才能被编码,因为20有太多因素。再联想到的消息作为通过重新排列Haskell中的列表进行编码和解码
i am st
rugglin
g hereX
被编码后,它读取, “IRGüaghmge lrsietnX”。
我明白如何通过添加'X'来使列表的长度合适,但我无法理解如何从列表中每隔第7个字符创建一个新列表。这是我的:
factors :: Int -> [Int]
factors n = [x | x <- [1..n], n `mod` x == 0]
anagramEncode :: [Char] -> [Char]
anagramEncode (x:xs) = if (length (factors (length xs))) == 4 then [k | k <-
???]
else anagramEncode (xs ++ ['X'])
答
让我们分解成步骤。
- 确定输入字符串长度为
>=
的最小2复合数字。 - 用
'X'
字符填充字符串的结尾,以使长度为2复合。 - 将填充的字符串拆分为每个块长度相同的块的列表。
- 调换块。
- 将大块连接在一起。
我们可以通过使用length
来获取输入字符串的长度。接下来,我们可以使用primes
包中的primeFactors
函数来查找只有2个素数因子的数字。
第二步可以使用++
和replicate n 'X'
将n
字符附加到字符串的末尾来完成。
第三步可以使用split
包中的chunksOf
函数,使用步骤1中的1个因子来完成,以便将字符串拆分为块。
最后2步很容易,因为这是transpose
和concat
函数。
import Data.List.Split (chunksOf)
import Data.Numbers.Primes (primeFactors)
import Data.List (transpose)
anagramEncode :: String -> String
anagramEncode str = concat (transpose (chunksOf factor paddedString))
where
unpaddedLength = length str
(paddedLength, factor) =
head [(n, facHi) | n <- [unpaddedLength ..]
, [facLo, facHi] <- [primeFactors n] ]
paddedString = str ++ replicate (paddedLength - unpaddedLength) 'X'
答
那么这里是我的解决方案。正如我在评论中提到的,Data.Matrix
包似乎是理想的工作,因为它的数据结构和内置的转置(行< - >列)能力。
所以这是代码;
import Data.Bool (bool)
import Data.Matrix
factors :: Int -> [(Int,Int)]
factors n = [(x, n `div` x) | x <- [2..limit], n `mod` x == 0]
where limit = truncate . sqrt . realToFrac $ n
twoComposites :: [(Int,Int)] -- infinite list of composites only with 2 composers
twoComposites = foldr (\n rs -> let ts = factors n -- tuples of composers
in bool rs (ts ++ rs) (length ts == 1)) [] [2..]
getComposites :: Int -> (Int,Int)
getComposites n = head . filter ((>= n) . uncurry (*)) $ twoComposites
composeMtx :: String -> Matrix Char
composeMtx s = uncurry fromList ts swx
where len = length s
ts = getComposites len
lwx = uncurry (*) $ ts -- length with X
swx = s ++ replicate (lwx - len) 'X' -- string with X
encode :: String -> String
encode = toList . transpose . composeMtx
注:它已经2AM在这里,我出来的啤酒和雪茄......因此,所有的详细说明将遵循明天。然而..让我们把它放在一些测试中...(也感谢@ 4castle指出我俯瞰)
*Main> encode "i am struggling here" -- 20 chrs adds one X fills up to (3,7)
"irg u aghmge lrsietn "
(0.01 secs, 155,240 bytes)
*Main> encode "i am struggling here " -- 21 chrs adds no Xs already (3,7)
"il ianmg shterrueg gX"
(0.01 secs, 159,160 bytes)
*Main> encode "i am struggling here " -- 22 chrs adds no Xs already (2,11)
"il ianmg shterrueg g "
(0.01 secs, 158,984 bytes)
*Main> encode "i am struggling here " -- 23 chrs adds 2 Xs fills up to (5,5)
"isg tlh arie munrX ggeX"
(0.01 secs, 159,448 bytes)
说明:
-
factors
是一种有效的函数来计算组成的数字。即检查100它只从2增加到10(sqrt 100)。 2产量(2,50),4产量(4,25),5产量(5,20),... 10产量(10,10)。我允许(10,10),尽管10是重复的,因为此算法需要使用作曲对来用于Matrix尺寸。 -
twoComposites
给我们合数只有2名作曲家的无限名单。该bool
功能(a -> a -> Bool -> a
)是一个三元测试就像JavaScript的? :
和需要3个参数,如bool negativeResponse positiveResponce condition
在Haskell左侧几乎总是负的。所以请记住,在JS不同。 -
getComposites
是一个函数,当用整数馈送返回具有两个作曲家其产生或者相同或者仅具有两个作曲家最接近更大合数的元组。uncurry
((a -> b -> c) -> (a, b) -> c
)函数接受一个运算符,该运算符接受2个参数并将其应用于具有两个元素的元组的元素。所以uncurry (*) (3,7)
将导致21 -
composeMtx
时用绳子垫它的“X的,并把它通过行中的矩阵行必要数量的喂养。
原来这就是它产生;
*Main> composeMtx "Once i had a black and white cat called Jessuro. He used to run on the roof all day long"
('O' 'n' 'c' 'e' ' ' 'i' ' ' 'h' 'a' 'd' ' ' 'a' ' ')
('b' 'l' 'a' 'c' 'k' ' ' 'a' 'n' 'd' ' ' 'w' 'h' 'i')
('t' 'e' ' ' 'c' 'a' 't' ' ' 'c' 'a' 'l' 'l' 'e' 'd')
(' ' 'J' 'e' 's' 's' 'u' 'r' 'o' '.' ' ' 'H' 'e' ' ')
('u' 's' 'e' 'd' ' ' 't' 'o' ' ' 'r' 'u' 'n' ' ' 'o')
('n' ' ' 't' 'h' 'e' ' ' 'r' 'o' 'o' 'f' ' ' 'a' 'l')
('l' ' ' 'd' 'a' 'y' ' ' 'l' 'o' 'n' 'g' 'X' 'X' 'X')
- 编码功能是非常简单的。你可能需要检查
Data.Matrix.transpose
左右;
*Main> encode "Once i had a black and white cat called Jessuro. He used to run on the roof all day long"
"Obt unlnleJs ca eetdeccsdha kas eyi tut a rorlhnco ooada.rond l ufg wlHn Xahee aX id olX"
(0.01 secs, 485,112 bytes)
你将如何利用每一个列表的第一个字符? –
当我使用(x:xs)时,不是列表的第一个字符? –
是的,但现在你想为每个子列表执行此操作。 –