Haskell 99 Questions :: 0x02

archive time: 2024-10-31

继续写写题目......

昨天写了前十题,今天我们继续写

题目

Question 11

Modified run-length encoding.

将之前的元组形式的 Run-length 编码改成使用 QCount 的形式

data QCount a = QSingle a | QMultiple Int a deriving (Show, Eq) qEncodeModified :: (Eq a) => [a] -> [QCount a]
答案
data QCount a = QSingle a | QMultiple Int a deriving (Show, Eq) qEncodeModified :: (Eq a) => [a] -> [QCount a] qEncodeModified lst = map qModify (qPack lst) where qModify :: (Eq a) => [a] -> QCount a qModify p = case qLength p of 1 -> QSingle (head p) len -> QMultiple len (head p)

Question 12

Decode a run-length encoded list.

解码 Run-length 编码

qRunLengthDecode :: [QCount a] -> [a]
答案
qRunLengthDecode :: [QCount a] -> [a] qRunLengthDecode clst = qReverse (qRunLengthDecodeI clst []) where qRunLengthDecodeI :: [QCount a] -> [a] -> [a] qRunLengthDecodeI [] acc = acc qRunLengthDecodeI (QSingle e : t) acc = qRunLengthDecodeI t (e : acc) qRunLengthDecodeI (QMultiple 0 _ : t) acc = qRunLengthDecodeI t acc qRunLengthDecodeI (QMultiple n e : t) acc = qRunLengthDecodeI (QMultiple (n - 1) e : t) (e : acc)

Question 13

Run-length encoding of a list (direct solution).

直接实现 Run-length 编码,不使用 Question 09 的结果, 实际上就是把 Question 09 的过程修改一下就好

qRunLengthEncodeDirect :: (Eq a) => [a] -> [QCount a]
答案
qRunLengthEncodeDirect :: (Eq a) => [a] -> [QCount a] qRunLengthEncodeDirect [] = [] qRunLengthEncodeDirect (h : t) = qReverse (qRunLengthEncodeDirectI t (1, h) []) where qTupleToCount :: (Int, a) -> QCount a qTupleToCount (n, e) = case n of 1 -> QSingle e _ -> QMultiple n e qRunLengthEncodeDirectI :: (Eq a) => [a] -> (Int, a) -> [QCount a] -> [QCount a] qRunLengthEncodeDirectI [] p acc = qTupleToCount p : acc qRunLengthEncodeDirectI (hI : tI) (n, e) acc | hI == e = qRunLengthEncodeDirectI tI (n + 1, e) acc | otherwise = qRunLengthEncodeDirectI tI (1, hI) (qTupleToCount (n, e) : acc)

Question 14

Duplicate the elements of a list.

将列表中每个元素都重复一次

qDuplicate :: [a] -> [a]
答案
qDuplicate :: [a] -> [a] qDuplicate lst = qReverse (qDuplicateI lst []) where qDuplicateI :: [a] -> [a] -> [a] qDuplicateI [] acc = acc qDuplicateI (h : t) acc = qDuplicateI t (h : h : acc)

Question 15

Replicate the elements of a list a given number of times.

将列表中每个元素都重复 n

qReplicate :: [a] -> Int -> [a]
答案
qReplicate :: [a] -> Int -> [a] qReplicate lst n = qReverse (qReplicateI lst 0 []) where qReplicateI :: [a] -> Int -> [a] -> [a] qReplicateI [] _ acc = acc qReplicateI (h : t) k acc | n == k = qReplicateI t 0 acc | otherwise = qReplicateI (h : t) (k + 1) (h : acc)

Question 16

Drop every N’th element from a list.

将列表中的 每个第 n 元素剔除

qDropEveryNth :: [a] -> Int -> [a]
答案
qDropEveryNth :: [a] -> Int -> [a] qDropEveryNth lst n = qReverse (qDropEveryNthI lst 1 []) where qDropEveryNthI :: [a] -> Int -> [a] -> [a] qDropEveryNthI [] _ acc = acc qDropEveryNthI (h : t) k acc | k == n = qDropEveryNthI t 1 acc | otherwise = qDropEveryNthI t (k + 1) (h : acc)

Question 17

Split a list into two parts; the length of the first part is given.

将列表分割成两个列表,其中第一个列表有 n 个元素

qSplitAt :: [a] -> Int -> ([a], [a])
答案
qSplitAt :: [a] -> Int -> ([a], [a]) qSplitAt lst n = qSplitAtI lst 0 [] where qSplitAtI :: [a] -> Int -> [a] -> ([a], [a]) qSplitAtI [] _ acc = (acc, []) qSplitAtI (h : t) k p | k == n = (qReverse p, h : t) | otherwise = qSplitAtI t (k + 1) (h : p)

Question 18

Extract a slice from a list.

返回一个列表切片

qSlice :: [a] -> Int -> Int -> [a]
答案
qSlice :: [a] -> Int -> Int -> [a] qSlice lst start end | start <= end = qReverse (qSliceI lst 1 []) | otherwise = [] where qSliceI :: [a] -> Int -> [a] -> [a] qSliceI [] _ acc = acc qSliceI (h : t) k acc | k < start = qSliceI t (k + 1) acc | k <= end = qSliceI t (k + 1) (h : acc) | otherwise = acc

Question 19

Rotate a list N places to the left.

将列表的前 n 个元素和后面元素翻转,负数表示倒数

qRotate :: [a] -> Int -> [a]
答案
qRotate :: [a] -> Int -> [a] qRotate lst k | abs k > len = lst | otherwise = (\(a, b) -> b ++ a) (qSplitAt lst (mod k len)) where len :: Int len = qLength lst

Question 20

Remove the K’th element from a list.

删除列表中的第 k 个元素,返回这个元素和修改后的列表

qRemoveAt :: [a] -> Int -> (a, [a])
答案
qRemoveAt :: [a] -> Int -> (Maybe a, [a]) qRemoveAt lst k = qRemoveAtI lst 1 [] where qRemoveAtI :: [a] -> Int -> [a] -> (Maybe a, [a]) qRemoveAtI [] _ acc = (Nothing, qReverse acc) qRemoveAtI (h : t) n acc | n == k = (Just h, qReverse acc ++ t) | otherwise = qRemoveAtI t (n + 1) (h : acc)

测试用例

这一部分的测试代码如下:

测试代码
module Part02 (part02) where import Qarks.Nnp ( QCount (..), qDropEveryNth, qDuplicate, qEncodeModified, qRemoveAt, qReplicate, qRotate, qRunLengthDecode, qRunLengthEncodeDirect, qSlice, qSplitAt, ) import Test.Hspec ( context, describe, it, shouldBe, ) import Test.Hspec.Runner (SpecWith) part02 :: SpecWith () part02 = describe "Part02" $ do context "Qarks.Nnp.qEncodeModified" $ do it "\"aaaabccaadeeee\"" $ do qEncodeModified "aaaabccaadeeee" `shouldBe` [ QMultiple 4 'a', QSingle 'b', QMultiple 2 'c', QMultiple 2 'a', QSingle 'd', QMultiple 4 'e' ] context "Qarks.Nnp.qRunLengthDecode" $ do it "[ QMultiple 4 'a', QSingle 'b', QMultiple 2 'c', QMultiple 2 'a', QSingle 'd', QMultiple 4 'e']" $ do qRunLengthDecode [ QMultiple 4 'a', QSingle 'b', QMultiple 2 'c', QMultiple 2 'a', QSingle 'd', QMultiple 4 'e' ] `shouldBe` "aaaabccaadeeee" context "Qarks.Nnp.qRunLengthEncodeDirect" $ do it "\"aaaabccaadeeee\"" $ do qRunLengthEncodeDirect "aaaabccaadeeee" `shouldBe` [ QMultiple 4 'a', QSingle 'b', QMultiple 2 'c', QMultiple 2 'a', QSingle 'd', QMultiple 4 'e' ] context "Qarks.Nnp.qDuplicate" $ do it "[1, 2, 3]" $ do qDuplicate [1 :: Int, 2, 3] `shouldBe` [1, 1, 2, 2, 3, 3] context "Qarks.Nnp.qReplicate" $ do it "\"abc\"" $ do qReplicate "abc" 3 `shouldBe` "aaabbbccc" context "Qarks.Nnp.qDropEveryNth" $ do it "3 of ['a' .. 'k']" $ do qDropEveryNth ['a' .. 'k'] 3 `shouldBe` "abdeghjk" context "Qarks.Nnp.qSplitAt" $ do it "3 of ['a' .. 'k']" $ do qSplitAt ['a' .. 'k'] 3 `shouldBe` ("abc", "defghijk") context "Qarks.Nnp.qSlice" $ do it "['a' .. 'k'] from 3 to 7" $ do qSlice ['a' .. 'k'] 3 7 `shouldBe` "cdefg" context "Qarks.Nnp.qRotate" $ do it "['a' .. 'h'] at 3" $ do qRotate ['a' .. 'h'] 3 `shouldBe` "defghabc" it "['a' .. 'h'] at -2" $ do qRotate ['a' .. 'h'] (-2) `shouldBe` "ghabcdef" context "Qarks.Nnp.qRemoveAt" $ do it "['a' .. 'd'] at 2" $ do qRemoveAt ['a' .. 'd'] 2 `shouldBe` (Just 'b', "acd")